copy: *.patch
-tar.bz2: kqemu name=kqemu-@version@.1 base=kqemu
+tar.gz: kqemu base=kqemu
copy: kqemu-permission
tar.bz2: qemu
tar.bz2: qemu-gtk name=qemu-gtk-20050716 base=
+version 0.7.2:
+
+- more precise segmentation support (aka Win98 support)
+- new API to track dirty RAM pages
+- CR4.TSD support
+- SYSENTER fix for x86_64
+- (Linux) added 'max_instances' module parameter
+- (win32) cpu interruption support (Filip Navara)
+- (win32) kqemu.inf installation file (Filip Navara)
+- IOPL restore fix (aka xen bug)
+
version 0.7.1-1:
- FreeBSD compile fixes - added x86_64 support
implied warranty. In no event will the author be held liable for
any damages arising from the use of this software.
-2) QEMU is a trademark of Fabrice Bellard.
+2) The header file "kqemu.h" can be freely used and distributed so
+ that it is possible to distribute QEMU binaries ready to use KQEMU.
+
+3) QEMU is a trademark of Fabrice Bellard.
Fabrice Bellard.
\ No newline at end of file
rm -f kqemu.o kqemu.ko kqemu-linux.o kqemu-mod.o kqemu.mod.c *~
FILES=Makefile README Changelog LICENSE install.sh kqemu-linux.c kqemu.h \
- kqemu-mod-i386.o kqemu-mod-x86_64.o \
+ kqemu-kernel.h kqemu-mod-i386.o kqemu-mod-x86_64.o \
kqemu-freebsd.c Makefile.freebsd \
- kqemu-win32.c kqemu.sys kqemu.reg kqemu-mod-i386-win32.o Makefile.winnt \
+ kqemu-win32.c kqemu.sys kqemu.inf kqemu-mod-i386-win32.o Makefile.winnt \
kqemu-doc.texi kqemu-doc.html
-VERSION=0.7.1-1
+VERSION=0.7.2
tar:
cd .. ; tar zcvf /tmp/kqemu-$(VERSION).tar.gz $(addprefix kqemu/, $(FILES))
<HTML>
<HEAD>
-<!-- Created by texi2html 1.56k from kqemu-doc.texi on 24 July 2005 -->
+<!-- Created by texi2html 1.56k from kqemu-doc.texi on 4 September 2005 -->
<TITLE>QEMU Accelerator User Documentation</TITLE>
</HEAD>
Module (KQEMU) is automatically activated provided you have the
necessary kernel headers. If nonetheless the compilation fails, you
can disable its compilation with the <SAMP>`--disable-kqemu'</SAMP>
-configure option.
+configure option.
+
+
+<P>
+Note that KQEMU cannot currently work if the Xen virtualizer is
+running on your host.
<P>
<P>
+If the major number 250 is already used by another driver, you can use
+the option <CODE>major=N</CODE> to set an alternate major number.
+
+
+<P>
If your distribution uses udev (like Fedora), use the kqemu module
option <CODE>major=0</CODE> to have the device <TT>`/dev/kqemu'</TT> automatically
created:
</PRE>
<P>
-It is usually necessary to change the device access rights by doing as
-root: <CODE>chmod 666 /dev/kqemu</CODE>.
-
-
-<P>
-If the major number 250 is already used by another driver, you can use
-the option <CODE>major=N</CODE> to set an alternate major number.
+It is usually necessary to change the device access rights set by
+udev. Edit <TT>`/etc/udev/permissions.d/50-udev.permissions'</TT> and add:
+<PRE>
+# kqemu
+kqemu:root:root:0666
+</PRE>
<H2><A NAME="SEC5" HREF="kqemu-doc.html#TOC5">2.3 QEMU Accelerator Installation for Windows</A></H2>
<P>
-Copy the kqemu driver <TT>`kqemu.sys'</TT> to
-<TT>`c:\winnt\system32\drivers'</TT>. Then do:
-
-<PRE>
-regedit kqemu.reg
-</PRE>
-
-<P>
-Now kqemu is installed and you must restart your system.
+Right click on <TT>`kqemu.inf'</TT> in Explorer and choose Install.
<P>
</DL>
<P>
-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
-<TT>`/dev/shm'</TT> directory to create this file because <CODE>tmpfs</CODE> is
-usually mounted on it (check with the shell command
-<CODE>df</CODE>). Otherwise <TT>`/tmp'</TT> is used as fallback. You can use the
-<VAR>QEMU_TMPDIR</VAR> shell variable to set a new directory for the QEMU
-RAM file.
+When using KQEMU on a Linux or FreeBSD host, 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 <TT>`/dev/shm'</TT> directory to create this
+file because <CODE>tmpfs</CODE> is usually mounted on it (check with the
+shell command <CODE>df</CODE>). Otherwise <TT>`/tmp'</TT> is used as
+fallback. You can use the <VAR>QEMU_TMPDIR</VAR> shell variable to set a
+new directory for the QEMU RAM file.
<P>
</PRE>
<P><HR><P>
-This document was generated on 24 July 2005 using
+This document was generated on 4 September 2005 using
<A HREF="http://wwwinfo.cern.ch/dis/texi2html/">texi2html</A> 1.56k.
</BODY>
</HTML>
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}
-configure option.
+configure option.
+
+Note that KQEMU cannot currently work if the Xen virtualizer is
+running on your host.
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,
in @file{/etc/rc.d/rc.local}.
+If the major number 250 is already used by another driver, you can use
+the option @code{major=N} to set an alternate major number.
+
If your distribution uses udev (like Fedora), use the kqemu module
option @code{major=0} to have the device @file{/dev/kqemu} automatically
created:
/sbin/modprobe kqemu major=0
@end example
-It is usually necessary to change the device access rights by doing as
-root: @code{chmod 666 /dev/kqemu}.
-
-If the major number 250 is already used by another driver, you can use
-the option @code{major=N} to set an alternate major number.
-
-@section QEMU Accelerator Installation for Windows
-
-Copy the kqemu driver @file{kqemu.sys} to
-@file{c:\winnt\system32\drivers}. Then do:
+It is usually necessary to change the device access rights set by
+udev. Edit @file{/etc/udev/permissions.d/50-udev.permissions} and add:
@example
-regedit kqemu.reg
+# kqemu
+kqemu:root:root:0666
@end example
-Now kqemu is installed and you must restart your system.
+@section QEMU Accelerator Installation for Windows
+
+Right click on @file{kqemu.inf} in Explorer and choose Install.
In order to start kqemu, you must do:
@example
emulation problems are coming from KQEMU.
@end table
-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.
+When using KQEMU on a Linux or FreeBSD host, 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
-/* $Id: kqemu-freebsd.c,v 1.3 2005/07/28 21:43:47 bellard Exp $ */
+/* $Id: kqemu-freebsd.c,v 1.4 2005/08/14 16:34:06 bellard Exp $ */
#include <sys/param.h>
#include <sys/systm.h>
#include <machine/vmparam.h>
#include <machine/stdarg.h>
-#define __KERNEL__
-
-#include "kqemu.h"
+#include "kqemu-kernel.h"
MALLOC_DECLARE(M_KQEMU);
MALLOC_DEFINE(M_KQEMU, "kqemu", "kqemu buffers");
--- /dev/null
+/*
+ * KQEMU kernel API
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ */
+#ifndef KQEMU_KERNEL_H
+#define KQEMU_KERNEL_H
+
+#include "kqemu.h"
+
+struct kqemu_state;
+
+#define CDECL __attribute__((regparm(0)))
+
+struct kqemu_state * CDECL kqemu_init(struct kqemu_init *d, int max_locked_pages);
+struct kqemu_cpu_state * CDECL kqemu_get_cpu_state(struct kqemu_state *s);
+long CDECL kqemu_exec(struct kqemu_state *s);
+void CDECL kqemu_delete(struct kqemu_state *s);
+
+/* callbacks */
+struct kqemu_page; /* opaque data for host page */
+struct kqemu_user_page; /* opaque data for host user page */
+
+struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
+ unsigned long user_addr);
+void CDECL kqemu_unlock_user_page(struct kqemu_user_page *page);
+
+struct kqemu_page *CDECL kqemu_alloc_zeroed_page(unsigned long *ppage_index);
+void CDECL kqemu_free_page(struct kqemu_page *page);
+void * CDECL kqemu_page_kaddr(struct kqemu_page *page);
+
+void * CDECL kqemu_vmalloc(unsigned int size);
+void CDECL kqemu_vfree(void *ptr);
+unsigned long CDECL kqemu_vmalloc_to_phys(const void *vaddr);
+
+void * CDECL kqemu_io_map(unsigned long page_index, unsigned int size);
+void CDECL kqemu_io_unmap(void *ptr, unsigned int size);
+
+int CDECL kqemu_schedule(void);
+
+void CDECL kqemu_log(const char *fmt, ...);
+
+#endif /* KQEMU_KERNEL_H */
#include <asm/uaccess.h>
#include <asm/io.h>
-#include "kqemu.h"
+#include "kqemu-kernel.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
#error "Linux 2.4.19 or above needed"
int major = 250;
MODULE_PARM(major,"i");
+/* configurable max_instances */
+int max_instances = 4;
+MODULE_PARM(max_instances,"i");
+
/* lock the page at virtual address 'user_addr' and return its
page index. Return -1 if error */
struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
/*********************************************************/
-#define KQEMU_MAX_INSTANCES 4
-
static int kqemu_nb_instances = 0;
static spinlock_t kqemu_lock = SPIN_LOCK_UNLOCKED;
static int max_locked_pages;
struct kqemu_instance *ks;
spin_lock(&kqemu_lock);
- if (kqemu_nb_instances >= KQEMU_MAX_INSTANCES) {
+ if (kqemu_nb_instances >= max_instances) {
spin_unlock(&kqemu_lock);
return -ENOMEM;
}
(KQEMU_VERSION >> 8) & 0xff,
(KQEMU_VERSION) & 0xff);
si_meminfo(&si);
- max_locked_pages = si.totalram / (2 * KQEMU_MAX_INSTANCES);
+ max_locked_pages = si.totalram / (2 * max_instances);
if (max_locked_pages > 32768)
max_locked_pages = 32768;
}
}
printk("KQEMU installed, max_instances=%d max_locked_mem=%dkB.\n",
- KQEMU_MAX_INSTANCES,
+ max_instances,
max_locked_pages * 4);
return 0;
}
typedef unsigned long long uint64_t;
#undef CDECL
-#define __KERNEL__
-#include "kqemu.h"
+#include "kqemu-kernel.h"
/* XXX: make it dynamic according to available RAM */
#define MAX_LOCKED_PAGES (16386 / 4)
+struct kqemu_instance {
+ struct kqemu_state *state;
+ PIRP current_irp;
+};
+
+FAST_MUTEX instance_lock;
+struct kqemu_instance *active_instance;
+
/* lock the page at virtual address 'user_addr' and return its
page index. Return -1 if error */
struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
mdl_pages = (PPFN_NUMBER)(mdl + 1);
MmInitializeMdl(mdl, user_addr, PAGE_SIZE);
+ /* XXX: Protect with SEH. */
MmProbeAndLockPages(mdl, KernelMode, IoModifyAccess);
*ppage_index = mdl_pages[0];
return (struct kqemu_user_page *)mdl;
execution) */
int CDECL kqemu_schedule(void)
{
- /* XXX: do it */
- return TRUE;
+ return active_instance->current_irp->Cancel;
}
void CDECL kqemu_log(const char *fmt, ...)
{
- /* XXX: format parameters */
- DbgPrint("%s", fmt);
-}
+ char log_buf[1024];
+ va_list ap;
-struct kqemu_instance {
- struct kqemu_state *state;
-};
+ va_start(ap, fmt);
+ _vsnprintf(log_buf, sizeof(log_buf), fmt, ap);
+ DbgPrint("kqemu: %s", log_buf);
+ va_end(ap);
+}
NTSTATUS STDCALL
KQemuCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
break;
}
+ ExAcquireFastMutex(&instance_lock);
+ active_instance = State;
+ State->current_irp = Irp;
+
ctx = kqemu_get_cpu_state(State->state);
RtlCopyMemory(ctx, Irp->AssociatedIrp.SystemBuffer,
sizeof(*ctx));
ret = kqemu_exec(State->state);
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, ctx, sizeof(*ctx));
+
+ ExReleaseFastMutex(&instance_lock);
+
Irp->IoStatus.Information = sizeof(*ctx);
Status = STATUS_SUCCESS;
}
VOID STDCALL
KQemuUnload(PDRIVER_OBJECT DriverObject)
{
+ UNICODE_STRING SymlinkName;
+
+ RtlInitUnicodeString(&SymlinkName, L"\\??\\kqemu");
+ IoDeleteSymbolicLink(&SymlinkName);
IoDeleteDevice(DriverObject->DeviceObject);
}
MmLockPagableCodeSection(DriverEntry);
+ ExInitializeFastMutex(&instance_lock);
+
DriverObject->MajorFunction[IRP_MJ_CREATE] = KQemuCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KQemuClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KQemuDeviceControl;
&DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE,
&DeviceObject);
if (!NT_SUCCESS(Status))
+ {
return Status;
+ }
/* Create the dos device link */
- IoCreateSymbolicLink(&SymlinkName, &DeviceName);
+ Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
+ if (!NT_SUCCESS(Status))
+ {
+ IoDeleteDevice(DeviceObject);
+ return Status;
+ }
return STATUS_SUCCESS;
}
+/*
+ * KQEMU header
+ *
+ * Copyright (c) 2004-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.
+ */
#ifndef KQEMU_H
#define KQEMU_H
-#define KQEMU_VERSION 0x010100
+#define KQEMU_VERSION 0x010200
struct kqemu_segment_cache {
uint32_t selector;
unsigned long dr6;
unsigned long dr7;
- int cpl; /* currently only 3 */
+ 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 */
#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)
};
struct kqemu_init {
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 */
};
#define KQEMU_RET_ABORT (-1)
#define KQEMU_GET_VERSION _IOR('q', 3, int)
#endif
-#ifdef __KERNEL__
-struct kqemu_state;
-
-#define CDECL __attribute__((regparm(0)))
-
-struct kqemu_state * CDECL kqemu_init(struct kqemu_init *d, int max_locked_pages);
-struct kqemu_cpu_state * CDECL kqemu_get_cpu_state(struct kqemu_state *s);
-long CDECL kqemu_exec(struct kqemu_state *s);
-void CDECL kqemu_delete(struct kqemu_state *s);
-
-/* callbacks */
-struct kqemu_page; /* opaque data for host page */
-struct kqemu_user_page; /* opaque data for host user page */
-
-struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
- unsigned long user_addr);
-void CDECL kqemu_unlock_user_page(struct kqemu_user_page *page);
-
-struct kqemu_page *CDECL kqemu_alloc_zeroed_page(unsigned long *ppage_index);
-void CDECL kqemu_free_page(struct kqemu_page *page);
-void * CDECL kqemu_page_kaddr(struct kqemu_page *page);
-
-void * CDECL kqemu_vmalloc(unsigned int size);
-void CDECL kqemu_vfree(void *ptr);
-unsigned long CDECL kqemu_vmalloc_to_phys(const void *vaddr);
-
-void * CDECL kqemu_io_map(unsigned long page_index, unsigned int size);
-void CDECL kqemu_io_unmap(void *ptr, unsigned int size);
-
-int CDECL kqemu_schedule(void);
-
-void CDECL kqemu_log(const char *fmt, ...);
-
-#endif
-
#endif /* KQEMU_H */
--- /dev/null
+; Copyright (C) 2005 Filip Navara, Damien Mascord
+
+[Version]
+Signature = "$Windows NT$"
+Class = System
+ClassGuid = {4D36E97D-E325-11CE-BFC1-08002BE10318}
+Provider = %Author%
+DriverVer = 04/28/2005,1.0
+
+[DestinationDirs]
+DefaultDestDir = 12
+KQemu.DriverFiles = 12
+KQemu.InfFiles = 10,inf
+
+[SourceDisksNames]
+1 = %InstDisk%
+
+[SourceDisksFiles]
+kqemu.sys = 1
+
+[Manufacturer]
+%Author% = KQemu.Manufacturer
+
+[KQemu.Manufacturer]
+%Description% = DefaultInstall,kqemu
+
+[DefaultInstall.NT]
+CopyFiles = KQemu.DriverFiles, KQemu.InfFiles
+AddReg = KQemu.UninstallRegistry
+
+[DefaultInstall.NT.Services]
+AddService = kqemu,,KQemuService_Inst
+
+[Uninstall.NT]
+DelFiles = KQemu.DriverFiles, KQemu.InfFiles
+DelReg = KQemu.UninstallRegistry
+
+[Uninstall.NT.Services]
+DelService = kqemu,0x00000200
+
+[KQemu.DriverFiles]
+kqemu.sys
+
+[KQemu.InfFiles]
+kqemu.inf
+
+[KQemu.UninstallRegistry]
+HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\KQEMU,"DisplayName",,%Description%
+HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\KQEMU,"UninstallString",0x20000,"RunDll32 setupapi.dll,InstallHinfSection Uninstall 132 %SystemRoot%\inf\kqemu.inf"
+
+[KQemuService_Inst]
+DisplayName = %Description%
+ServiceType = %SERVICE_KERNEL_DRIVER%
+StartType = %SERVICE_DEMAND_START%
+ErrorControl = %SERVICE_ERROR_NORMAL%
+ServiceBinary = %12%\kqemu.sys
+
+[Strings]
+Author = "Fabrice Bellard"
+Description = "KQEMU virtualisation module for QEMU"
+InstDisk = "KQEMU Install Disk"
+SERVICE_KERNEL_DRIVER = 1
+SERVICE_DEMAND_START = 3
+SERVICE_ERROR_NORMAL = 1
+++ /dev/null
-REGEDIT4\r
-\r
-[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\kqemu]\r
-"Type"=dword:00000001\r
-"Start"=dword:00000003\r
-"ErrorControl"=dword:00000001\r
-"DisplayName"="kqemu"\r
--- /dev/null
+diff -Naur qemu-0.7.2/configure qemu-0.7.2-gtk/configure
+--- qemu-0.7.2/configure 2005-09-20 11:35:05 +0400
++++ qemu-0.7.2-gtk/configure 2005-09-20 11:34:49 +0400
+@@ -15,6 +15,7 @@
+ TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
+ TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
+ TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
++TMPF="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}-conf"
+
+ # default parameters
+ prefix=""
+@@ -171,6 +172,10 @@
+ ;;
+ --disable-sdl) sdl="no"
+ ;;
++ --enable-gtk) gtk="yes"
++ ;;
++ --set-fs-driver=*) fsdrv=`echo $opt | cut -d '=' -f 2`
++ ;;
+ --enable-fmod) fmod="yes"
+ ;;
+ --fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
+@@ -319,6 +324,64 @@
+ fi # cross compilation
+ fi # -z $sdl
+
++##########################################
++# GTK probe
++
++gtk_too_old=no
++
++if test -z "$gtk" ; then
++
++gtk=no
++
++# normal GTK probe
++cat > $TMPC << EOF
++#include <stdlib.h>
++#include <gtk/gtk.h>
++int main(int argc, char **argv) { gtk_init(&argc, &argv); return EXIT_SUCCESS; }
++EOF
++
++if $cc -o $TMPE `pkg-config --cflags --libs gtk+-2.0 2> /dev/null` $TMPC 2> /dev/null ; then
++_gtkversion=`pkg-config --modversion gtk+-2.0 | sed 's/[^0-9]//g'`
++if test "$_sdlversion" -lt 240 ; then
++ gtk_too_old=yes
++else
++ gtk=yes
++
++fi
++
++fi # gtk compile test
++
++fi # -z $gtk
++
++if [ "$gtk" = "yes" ]; then
++
++if [ "$fsdrv" = "" ] ; then
++
++if [ "$bsd" = "yes" -o "$linux" = "yes" ]; then
++ fsdrv=xvid_fs.c
++else
++ fsdrv=null_fs.c
++fi
++
++fi # fsdrv test
++
++if [ "$fsdrv" = "xvid_fs.c" -o "$fsdrv" = "null_fs.c" ]; then
++ echo "fsdrv=$fsdrv" >> $TMPF
++else
++ echo "Warning: unknown gtk fullscreen driver: $fsdrv - using null driver"
++ echo 'fsdrv=null_fs.c' >> $TMPF
++ fsdrv=null_fs.c
++fi
++
++if [ "$fsdrv" = "xvid_fs.c" ]; then
++ FS_LIBS="-lX11 -lXxf86vm -lXext"
++ [ "$cpu" = "x86_64" ] && lib=lib64
++ FS_LIBS="$FS_LIBS -L/usr/X11R6/${lib:-lib}"
++ echo FS_LIBS=\"$FS_LIBS\" >> $TMPF
++fi
++
++fi # gtk=yes test
++
+ if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
+ cat << EOF
+
+@@ -408,6 +471,8 @@
+ if test "$sdl" != "no" ; then
+ echo "SDL static link $sdl_static"
+ fi
++echo "GTK support $gtk"
++echo "GTK FS driver $fsdrv"
+ echo "mingw32 support $mingw32"
+ echo "Adlib support $adlib"
+ echo -n "FMOD support $fmod"
+@@ -624,6 +689,8 @@
+ interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
+ echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
+
++. $TMPF
++
+ if test "$target_cpu" = "i386" ; then
+ echo "TARGET_ARCH=i386" >> $config_mak
+ echo "#define TARGET_ARCH \"i386\"" >> $config_h
+@@ -710,6 +777,17 @@
+ fi
+ fi
+
++if test "$gtk" = "yes" ; then
++ . $TMPF
++ echo "#define CONFIG_GTK 1" >> $config_h
++ echo "CONFIG_GTK=yes" >> $config_mak
++ echo "GTK_LIBS=`pkg-config --libs gtk+-2.0`" >> $config_mak
++ echo "GTK_CFLAGS=`pkg-config --cflags gtk+-2.0`" >> $config_mak
++ echo "FSDRV=$fsdrv" >> $config_mak
++ echo "FS_LIBS=$FS_LIBS" >> $config_mak
++ echo "" >> $config_mak
++fi
++
+ if test "$cocoa" = "yes" ; then
+ echo "#define CONFIG_COCOA 1" >> $config_h
+ echo "CONFIG_COCOA=yes" >> $config_mak
+@@ -729,4 +807,4 @@
+ done
+ fi
+
+-rm -f $TMPO $TMPC $TMPE $TMPS
++rm -f $TMPO $TMPC $TMPE $TMPS $TMPF
+diff -Naur qemu-0.7.2/Makefile.target qemu-0.7.2-gtk/Makefile.target
+--- qemu-0.7.2/Makefile.target 2005-09-20 11:35:05 +0400
++++ qemu-0.7.2-gtk/Makefile.target 2005-09-20 11:34:49 +0400
+@@ -314,6 +314,13 @@
+ ifdef CONFIG_SDL
+ VL_OBJS+=sdl.o
+ endif
++ifdef CONFIG_GTK
++VL_OBJS+=gtk2.o
++VL_OBJS+=callbacks.o
++VL_OBJS+=interface.o
++VL_OBJS+=support.o
++VL_OBJS+=fullscreen.o
++endif
+ ifdef CONFIG_COCOA
+ VL_OBJS+=cocoa.o
+ COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa
+@@ -350,7 +357,7 @@
+ endif
+
+ $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
+- $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
++ $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(GTK_LIBS) $(FS_LIBS) $(VL_LIBS)
+
+ cocoa.o: cocoa.m
+ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+@@ -358,6 +365,21 @@
+ sdl.o: sdl.c keymaps.c sdl_keysym.h
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
++gtk2.o: gtk2gui.c keymaps.c gdk_keysym.h fullscreen.h interface.h callbacks.h support.h
++ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
++
++callbacks.o: callbacks.c callbacks.h interface.h support.h
++ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
++
++support.o: support.c callbacks.h interface.h support.h
++ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
++
++interface.o: interface.c callbacks.h interface.h support.h
++ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
++
++fullscreen.o: $(FSDRV) fullscreen.h
++ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
++
+ sdlaudio.o: sdlaudio.c
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+diff -Naur qemu-0.7.2/vl.c qemu-0.7.2-gtk/vl.c
+--- qemu-0.7.2/vl.c 2005-09-04 21:11:31 +0400
++++ qemu-0.7.2-gtk/vl.c 2005-09-20 11:34:49 +0400
+@@ -147,10 +147,13 @@
+ TextConsole *vga_console;
+ CharDriverState *serial_hds[MAX_SERIAL_PORTS];
+ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
++int use_gtk = 0;
+ #ifdef TARGET_I386
+ int win2k_install_hack = 0;
+ #endif
+
++void gui_checkargs(int *, char ***);
++
+ /***********************************************************/
+ /* x86 ISA bus support */
+
+@@ -2966,6 +2969,7 @@
+ QEMU_OPTION_cirrusvga,
+ QEMU_OPTION_g,
+ QEMU_OPTION_std_vga,
++ QEMU_OPTION_use_gtk,
+ QEMU_OPTION_monitor,
+ QEMU_OPTION_serial,
+ QEMU_OPTION_parallel,
+@@ -3037,6 +3041,7 @@
+ { "localtime", 0, QEMU_OPTION_localtime },
+ { "isa", 0, QEMU_OPTION_isa },
+ { "std-vga", 0, QEMU_OPTION_std_vga },
++ { "use-gtk", 0, QEMU_OPTION_use_gtk },
+ { "monitor", 1, QEMU_OPTION_monitor },
+ { "serial", 1, QEMU_OPTION_serial },
+ { "parallel", 1, QEMU_OPTION_parallel },
+@@ -3471,6 +3476,9 @@
+ case QEMU_OPTION_std_vga:
+ cirrus_vga_enabled = 0;
+ break;
++ case QEMU_OPTION_use_gtk:
++ use_gtk = 1;
++ break;
+ case QEMU_OPTION_g:
+ {
+ const char *p;
+@@ -3565,6 +3573,7 @@
+ boot_device = 'd';
+ }
+
++ gui_checkargs(&argc, &argv);
+ #if !defined(CONFIG_SOFTMMU)
+ /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
+ {
+@@ -3727,7 +3736,17 @@
+ if (nographic) {
+ dumb_display_init(ds);
+ } else {
++#if defined(CONFIG_GTK)
+ #if defined(CONFIG_SDL)
++ /* so we can choose */
++ if (use_gtk)
++ gtk2_display_init(ds, full_screen);
++ else
++ sdl_display_init(ds, full_screen);
++#else
++ gtk2_display_init(ds, full_screen);
++#endif
++#elif defined(CONFIG_SDL)
+ sdl_display_init(ds, full_screen);
+ #elif defined(CONFIG_COCOA)
+ cocoa_display_init(ds, full_screen);
+diff -Naur qemu-0.7.2/vl.h qemu-0.7.2-gtk/vl.h
+--- qemu-0.7.2/vl.h 2005-09-04 21:11:31 +0400
++++ qemu-0.7.2-gtk/vl.h 2005-09-20 11:34:49 +0400
+@@ -612,6 +612,9 @@
+ /* sdl.c */
+ void sdl_display_init(DisplayState *ds, int full_screen);
+
++/* gtk2.c */
++void gtk2_display_init(DisplayState *ds, int full_screen);
++
+ /* cocoa.m */
+ void cocoa_display_init(DisplayState *ds, int full_screen);
+
+++ /dev/null
-diff -u qemu.orig/Makefile.target qemu/Makefile.target
---- qemu.orig/Makefile.target Sat Jul 16 18:00:05 2005
-+++ qemu/Makefile.target Sat Jul 16 17:58:18 2005
-@@ -361,6 +361,13 @@
- ifdef CONFIG_SDL
- VL_OBJS+=sdl.o
- endif
-+ifdef CONFIG_GTK
-+VL_OBJS+=gtk2.o
-+VL_OBJS+=callbacks.o
-+VL_OBJS+=interface.o
-+VL_OBJS+=support.o
-+VL_OBJS+=fullscreen.o
-+endif
- ifdef CONFIG_COCOA
- VL_OBJS+=cocoa.o
- COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa
-@@ -396,13 +403,28 @@
- endif
-
- $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
-- $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
-+ $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(GTK_LIBS) $(FS_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 $@ $<
-+
-+gtk2.o: gtk2gui.c keymaps.c gdk_keysym.h fullscreen.h interface.h callbacks.h support.h
-+ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+callbacks.o: callbacks.c callbacks.h interface.h support.h
-+ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+support.o: support.c callbacks.h interface.h support.h
-+ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+interface.o: interface.c callbacks.h interface.h support.h
-+ $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+fullscreen.o: $(FSDRV) fullscreen.h
-+ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
-
- sdlaudio.o: sdlaudio.c
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-diff -u qemu.orig/configure qemu/configure
---- qemu.orig/configure Mon May 30 19:40:14 2005
-+++ qemu/configure Mon May 30 20:10:11 2005
-@@ -15,6 +15,7 @@
- TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
- TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
- TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
-+TMPF="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}-conf"
-
- # default parameters
- prefix=""
-@@ -171,6 +172,10 @@
- ;;
- --disable-sdl) sdl="no"
- ;;
-+ --enable-gtk) gtk="yes"
-+ ;;
-+ --set-fs-driver=*) fsdrv=`echo $opt | cut -d '=' -f 2`
-+ ;;
- --enable-fmod) fmod="yes"
- ;;
- --fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
-@@ -311,6 +316,64 @@
- fi # cross compilation
- fi # -z $sdl
-
-+##########################################
-+# GTK probe
-+
-+gtk_too_old=no
-+
-+if test -z "$gtk" ; then
-+
-+gtk=no
-+
-+# normal GTK probe
-+cat > $TMPC << EOF
-+#include <stdlib.h>
-+#include <gtk/gtk.h>
-+int main(int argc, char **argv) { gtk_init(&argc, &argv); return EXIT_SUCCESS; }
-+EOF
-+
-+if $cc -o $TMPE `pkg-config --cflags --libs gtk+-2.0 2> /dev/null` $TMPC 2> /dev/null ; then
-+_gtkversion=`pkg-config --modversion gtk+-2.0 | sed 's/[^0-9]//g'`
-+if test "$_sdlversion" -lt 240 ; then
-+ gtk_too_old=yes
-+else
-+ gtk=yes
-+
-+fi
-+
-+fi # gtk compile test
-+
-+fi # -z $gtk
-+
-+if [ "$gtk" = "yes" ]; then
-+
-+if [ "$fsdrv" = "" ] ; then
-+
-+if [ "$bsd" = "yes" -o "$linux" = "yes" ]; then
-+ fsdrv=xvid_fs.c
-+else
-+ fsdrv=null_fs.c
-+fi
-+
-+fi # fsdrv test
-+
-+if [ "$fsdrv" = "xvid_fs.c" -o "$fsdrv" = "null_fs.c" ]; then
-+ echo "fsdrv=$fsdrv" >> $TMPF
-+else
-+ echo "Warning: unknown gtk fullscreen driver: $fsdrv - using null driver"
-+ echo 'fsdrv=null_fs.c' >> $TMPF
-+ fsdrv=null_fs.c
-+fi
-+
-+if [ "$fsdrv" = "xvid_fs.c" ]; then
-+ FS_LIBS="-lX11 -lXxf86vm -lXext"
-+ [ "$cpu" = "x86_64" ] && lib=lib64
-+ FS_LIBS="$FS_LIBS -L/usr/X11R6/${lib:-lib}"
-+ echo FS_LIBS=\"$FS_LIBS\" >> $TMPF
-+fi
-+
-+fi # gtk=yes test
-+
- if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
- cat << EOF
-
-@@ -434,6 +495,8 @@
- if test "$sdl" != "no" ; then
- echo "SDL static link $sdl_static"
- fi
-+echo "GTK support $gtk"
-+echo "GTK FS driver $fsdrv"
- echo "mingw32 support $mingw32"
- echo "Adlib support $adlib"
- echo -n "FMOD support $fmod"
-@@ -643,6 +706,8 @@
- interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
- echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
-
-+. $TMPF
-+
- if test "$target_cpu" = "i386" ; then
- echo "TARGET_ARCH=i386" >> $config_mak
- echo "#define TARGET_ARCH \"i386\"" >> $config_h
-@@ -720,6 +785,17 @@
- fi
- fi
-
-+if test "$gtk" = "yes" ; then
-+ . $TMPF
-+ echo "#define CONFIG_GTK 1" >> $config_h
-+ echo "CONFIG_GTK=yes" >> $config_mak
-+ echo "GTK_LIBS=`pkg-config --libs gtk+-2.0`" >> $config_mak
-+ echo "GTK_CFLAGS=`pkg-config --cflags gtk+-2.0`" >> $config_mak
-+ echo "FSDRV=$fsdrv" >> $config_mak
-+ echo "FS_LIBS=$FS_LIBS" >> $config_mak
-+ echo "" >> $config_mak
-+fi
-+
- if test "$cocoa" = "yes" ; then
- echo "#define CONFIG_COCOA 1" >> $config_h
- echo "CONFIG_COCOA=yes" >> $config_mak
-@@ -739,4 +815,4 @@
- done
- fi
-
--rm -f $TMPO $TMPC $TMPE $TMPS
-+rm -f $TMPO $TMPC $TMPE $TMPS $TMPF
-diff -u qemu.orig/vl.h qemu/vl.h
---- qemu.orig/vl.h Mon May 30 19:40:14 2005
-+++ qemu/vl.h Sat May 28 16:16:18 2005
-@@ -579,6 +579,9 @@
- /* sdl.c */
- void sdl_display_init(DisplayState *ds, int full_screen);
-
-+/* gtk2.c */
-+void gtk2_display_init(DisplayState *ds, int full_screen);
-+
- /* cocoa.m */
- void cocoa_display_init(DisplayState *ds, int full_screen);
-
-diff -u qemu.orig/vl.c qemu/vl.c
---- qemu.orig/vl.c Tue May 31 14:53:22 2005
-+++ qemu/vl.c Tue May 31 14:52:55 2005
-@@ -147,10 +147,13 @@
- TextConsole *vga_console;
- CharDriverState *serial_hds[MAX_SERIAL_PORTS];
- CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
-+int use_gtk = 0;
- #ifdef TARGET_I386
- int win2k_install_hack = 0;
- #endif
-
-+void gui_checkargs(int *, char ***);
-+
- /***********************************************************/
- /* x86 ISA bus support */
-
-@@ -2877,6 +2878,7 @@
- QEMU_OPTION_cirrusvga,
- QEMU_OPTION_g,
- QEMU_OPTION_std_vga,
-+ QEMU_OPTION_use_gtk,
- QEMU_OPTION_monitor,
- QEMU_OPTION_serial,
- QEMU_OPTION_parallel,
-@@ -2947,6 +2949,7 @@
- { "localtime", 0, QEMU_OPTION_localtime },
- { "isa", 0, QEMU_OPTION_isa },
- { "std-vga", 0, QEMU_OPTION_std_vga },
-+ { "use-gtk", 0, QEMU_OPTION_use_gtk },
- { "monitor", 1, QEMU_OPTION_monitor },
- { "serial", 1, QEMU_OPTION_serial },
- { "parallel", 1, QEMU_OPTION_parallel },
-@@ -3345,6 +3348,9 @@
- case QEMU_OPTION_std_vga:
- cirrus_vga_enabled = 0;
- break;
-+ case QEMU_OPTION_use_gtk:
-+ use_gtk = 1;
-+ break;
- case QEMU_OPTION_g:
- {
- const char *p;
-@@ -3090,6 +3092,7 @@
- const char *loadvm = NULL;
- QEMUMachine *machine;
-
-+ gui_checkargs(&argc, &argv);
- #if !defined(CONFIG_SOFTMMU)
- /* we never want that malloc() uses mmap() */
- mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
-@@ -3599,7 +3605,17 @@
- if (nographic) {
- dumb_display_init(ds);
- } else {
-+#if defined(CONFIG_GTK)
- #if defined(CONFIG_SDL)
-+ /* so we can choose */
-+ if (use_gtk)
-+ gtk2_display_init(ds, full_screen);
-+ else
-+ sdl_display_init(ds, full_screen);
-+#else
-+ gtk2_display_init(ds, full_screen);
-+#endif
-+#elif defined(CONFIG_SDL)
- sdl_display_init(ds, full_screen);
- #elif defined(CONFIG_COCOA)
- cocoa_display_init(ds, full_screen);
%define kmodule_name kqemu
-%define kqemuver 0.7.1.1
+%define kqemuver 0.7.2
%define gtkver 20050716
Name: qemu
-Version: 0.7.1
+Version: 0.7.2
Release: alt1
Summary: QEMU CPU Emulator
URL: http://fabrice.bellard.free.fr/qemu/
Source: %name-%version.tar.bz2
-Source1: kqemu-%kqemuver.tar.bz2
+Source1: kqemu-%kqemuver.tar.gz
Source2: kqemu-permission
Source3: qemu-gtk-%gtkver.tar.bz2
Patch: %name-0.7.1-alt-makefile.patch
Patch1: %name-0.6.2-alt-hdtrans.patch
Patch2: %name-0.7.0-alt-kqemu.patch
-Patch3: %name-0.7.1-alt-guiargs.patch
+Patch3: %name-0.7.2-gtk.patch
+Patch4: %name-0.7.1-alt-guiargs.patch
# for %_bindir/qemu*
%set_verify_elf_method textrel=relaxed
+# for proll.elf
+%add_strip_skiplist *%_datadir/*
-BuildRequires: libSDL-devel-static xorg-x11-devel-static
-BuildRequires: glibc-devel-static zlib-devel-static
-BuildRequires: libaudiofile-devel-static esound-devel-static libalsa-devel-static
+BuildRequires: libSDL-devel xorg-x11-devel
+BuildRequires: glibc-devel zlib-devel
+BuildRequires: libaudiofile-devel esound-devel libalsa-devel
BuildRequires: tetex-core libgtk+2-devel
%description
%patch -p1
%patch1 -p1
%patch2 -p0
-%__patch -p1 < qemu-gtk-patch.diff
%patch3 -p1
+%patch4 -p1
%__cp -a kqemu kernel-source-%kmodule_name-%kqemuver
%__cp -a %SOURCE2 kernel-source-%kmodule_name-%kqemuver/PERMISSION
%_usrsrc/kernel/sources/*
%changelog
+* Tue Sep 20 2005 Kachalov Anton <mouse@altlinux.ru> 0.7.2-alt1
+- 0.7.2
+- Updated Kqemu to 0.7.2
+
* Thu Aug 04 2005 Kachalov Anton <mouse@altlinux.ru> 0.7.1-alt1
- 0.7.1
- Updated:
+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)
- 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:
TAGS:
etags *.[ch] tests/*.[ch]
+cscope:
+ rm -f ./cscope.*
+ find . -name "*.[ch]" -print > ./cscope.files
+ cscope -b
+
# documentation
%.html: %.texi
texi2html -monolithic -number $<
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)
-0.7.1
\ No newline at end of file
+0.7.2
\ No newline at end of file
FreeBSD)
bsd="yes"
oss="yes"
-if [ "$cpu" = "i386" ] ; then
+if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
fi
;;
#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);
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, ...));
#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 */
#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)) {
#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"\
#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"\
#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: ;\
/* 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;
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)
{
(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));
}
#endif
}
#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)
{
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);
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
{
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);
+
+#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 (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,
}
}
-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;
length = end - start;
if (length == 0)
return;
+ len = length >> TARGET_PAGE_BITS;
+ env = cpu_single_env;
+#ifdef USE_KQEMU
+ if (env->kqemu_enabled) {
+ 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);
- 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
when accessing the range */
start1 = start + (unsigned long)phys_ram_base;
#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)
{
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);
{
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;
/* 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;
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;
+ 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);
}
-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;
+ 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);
}
-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;
+ 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);
}
-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,
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
}
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 */
+ /* 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;
/* 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 & ~CODE_DIRTY_FLAG);
+ }
}
} 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)) {
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;
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);
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 {
}
/* warning: addr must be aligned */
-/* XXX: optimize code invalidation test */
void stl_phys(target_phys_addr_t addr, uint32_t val)
{
int io_index;
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 {
/* 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 & ~CODE_DIRTY_FLAG);
+ }
}
}
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
extern FILE *logfile;
+static PITState *pit;
+
static void pic_irq_request(void *opaque, int level)
{
if (level) {
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)
}
#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)
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);
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;
#ifdef USE_KQEMU
#define DEBUG
+//#define PROFILE
#include <unistd.h>
#include <fcntl.h>
#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"
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) \
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
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;
kqemu_update_cpuid(env);
env->kqemu_enabled = 1;
nb_pages_to_flush = 0;
+ nb_ram_pages_to_update = 0;
return 0;
}
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
+ /* 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
+ ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr;
+}
+
struct fpstate {
uint16_t fpuc;
uint16_t dummy1;
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;
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)
}
#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);
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);
#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);
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
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);
* - 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)
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
static void do_quit(void)
{
+#ifdef USE_KQEMU
+ kqemu_record_dump();
+#endif
exit(0);
}
<HTML>
<HEAD>
-<!-- Created by texi2html 1.56k from qemu-doc.texi on 24 July 2005 -->
+<!-- Created by texi2html 1.56k from qemu-doc.texi on 4 September 2005 -->
<TITLE>QEMU CPU Emulator User Documentation</TITLE>
</HEAD>
<LI><A NAME="TOC27" HREF="qemu-doc.html#SEC27">3.10.2.1 SVGA graphic modes support</A>
<LI><A NAME="TOC28" HREF="qemu-doc.html#SEC28">3.10.2.2 CPU usage reduction</A>
<LI><A NAME="TOC29" HREF="qemu-doc.html#SEC29">3.10.2.3 Windows 2000 disk full problem</A>
-<LI><A NAME="TOC30" HREF="qemu-doc.html#SEC30">3.10.2.4 Windows XP security problems</A>
+<LI><A NAME="TOC30" HREF="qemu-doc.html#SEC30">3.10.2.4 Windows 2000 shutdown</A>
+<LI><A NAME="TOC31" HREF="qemu-doc.html#SEC31">3.10.2.5 Share a directory between Unix and Windows</A>
+<LI><A NAME="TOC32" HREF="qemu-doc.html#SEC32">3.10.2.6 Windows XP security problems</A>
</UL>
-<LI><A NAME="TOC31" HREF="qemu-doc.html#SEC31">3.10.3 MS-DOS and FreeDOS</A>
+<LI><A NAME="TOC33" HREF="qemu-doc.html#SEC33">3.10.3 MS-DOS and FreeDOS</A>
<UL>
-<LI><A NAME="TOC32" HREF="qemu-doc.html#SEC32">3.10.3.1 CPU usage reduction</A>
+<LI><A NAME="TOC34" HREF="qemu-doc.html#SEC34">3.10.3.1 CPU usage reduction</A>
</UL>
</UL>
</UL>
-<LI><A NAME="TOC33" HREF="qemu-doc.html#SEC33">4. QEMU PowerPC System emulator invocation</A>
-<LI><A NAME="TOC34" HREF="qemu-doc.html#SEC34">5. Sparc32 System emulator invocation</A>
-<LI><A NAME="TOC35" HREF="qemu-doc.html#SEC35">6. Sparc64 System emulator invocation</A>
-<LI><A NAME="TOC36" HREF="qemu-doc.html#SEC36">7. MIPS System emulator invocation</A>
-<LI><A NAME="TOC37" HREF="qemu-doc.html#SEC37">8. QEMU User space emulator invocation</A>
+<LI><A NAME="TOC35" HREF="qemu-doc.html#SEC35">4. QEMU PowerPC System emulator invocation</A>
+<LI><A NAME="TOC36" HREF="qemu-doc.html#SEC36">5. Sparc32 System emulator invocation</A>
+<LI><A NAME="TOC37" HREF="qemu-doc.html#SEC37">6. Sparc64 System emulator invocation</A>
+<LI><A NAME="TOC38" HREF="qemu-doc.html#SEC38">7. MIPS System emulator invocation</A>
+<LI><A NAME="TOC39" HREF="qemu-doc.html#SEC39">8. QEMU User space emulator invocation</A>
<UL>
-<LI><A NAME="TOC38" HREF="qemu-doc.html#SEC38">8.1 Quick Start</A>
-<LI><A NAME="TOC39" HREF="qemu-doc.html#SEC39">8.2 Wine launch</A>
-<LI><A NAME="TOC40" HREF="qemu-doc.html#SEC40">8.3 Command line options</A>
+<LI><A NAME="TOC40" HREF="qemu-doc.html#SEC40">8.1 Quick Start</A>
+<LI><A NAME="TOC41" HREF="qemu-doc.html#SEC41">8.2 Wine launch</A>
+<LI><A NAME="TOC42" HREF="qemu-doc.html#SEC42">8.3 Command line options</A>
</UL>
-<LI><A NAME="TOC41" HREF="qemu-doc.html#SEC41">9. Compilation from the sources</A>
+<LI><A NAME="TOC43" HREF="qemu-doc.html#SEC43">9. Compilation from the sources</A>
<UL>
-<LI><A NAME="TOC42" HREF="qemu-doc.html#SEC42">9.1 Linux/Unix</A>
+<LI><A NAME="TOC44" HREF="qemu-doc.html#SEC44">9.1 Linux/Unix</A>
<UL>
-<LI><A NAME="TOC43" HREF="qemu-doc.html#SEC43">9.1.1 Compilation</A>
-<LI><A NAME="TOC44" HREF="qemu-doc.html#SEC44">9.1.2 Tested tool versions</A>
+<LI><A NAME="TOC45" HREF="qemu-doc.html#SEC45">9.1.1 Compilation</A>
+<LI><A NAME="TOC46" HREF="qemu-doc.html#SEC46">9.1.2 Tested tool versions</A>
</UL>
-<LI><A NAME="TOC45" HREF="qemu-doc.html#SEC45">9.2 Windows</A>
-<LI><A NAME="TOC46" HREF="qemu-doc.html#SEC46">9.3 Cross compilation for Windows with Linux</A>
-<LI><A NAME="TOC47" HREF="qemu-doc.html#SEC47">9.4 Mac OS X</A>
+<LI><A NAME="TOC47" HREF="qemu-doc.html#SEC47">9.2 Windows</A>
+<LI><A NAME="TOC48" HREF="qemu-doc.html#SEC48">9.3 Cross compilation for Windows with Linux</A>
+<LI><A NAME="TOC49" HREF="qemu-doc.html#SEC49">9.4 Mac OS X</A>
</UL>
</UL>
<P><HR><P>
<H1><A NAME="SEC3" HREF="qemu-doc.html#TOC3">2. Installation</A></H1>
<P>
-If you want to compile QEMU yourself, see section <A HREF="qemu-doc.html#SEC41">9. Compilation from the sources</A>.
+If you want to compile QEMU yourself, see section <A HREF="qemu-doc.html#SEC43">9. Compilation from the sources</A>.
<P>
If a precompiled package is available for your distribution - you just
-have to install it. Otherwise, see section <A HREF="qemu-doc.html#SEC41">9. Compilation from the sources</A>.
+have to install it. Otherwise, see section <A HREF="qemu-doc.html#SEC43">9. Compilation from the sources</A>.
Note that a SAMBA server must be installed on the host OS in
<TT>`/usr/sbin/smbd'</TT>. 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.
<DT><SAMP>`-redir [tcp|udp]:host-port:[guest-host]:guest-port'</SAMP>
<DD>
-<H4><A NAME="SEC30" HREF="qemu-doc.html#TOC30">3.10.2.4 Windows XP security problems</A></H4>
+<H4><A NAME="SEC30" HREF="qemu-doc.html#TOC30">3.10.2.4 Windows 2000 shutdown</A></H4>
+
+<P>
+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.
+
+
+<P>
+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.
+
+
+
+
+<H4><A NAME="SEC31" HREF="qemu-doc.html#TOC31">3.10.2.5 Share a directory between Unix and Windows</A></H4>
+
+<P>
+See section <A HREF="qemu-doc.html#SEC10">3.3 Invocation</A> about the help of the option <SAMP>`-smb'</SAMP>.
+
+
+
+
+<H4><A NAME="SEC32" HREF="qemu-doc.html#TOC32">3.10.2.6 Windows XP security problems</A></H4>
<P>
Some releases of Windows XP install correctly but give a security
-<H3><A NAME="SEC31" HREF="qemu-doc.html#TOC31">3.10.3 MS-DOS and FreeDOS</A></H3>
+<H3><A NAME="SEC33" HREF="qemu-doc.html#TOC33">3.10.3 MS-DOS and FreeDOS</A></H3>
-<H4><A NAME="SEC32" HREF="qemu-doc.html#TOC32">3.10.3.1 CPU usage reduction</A></H4>
+<H4><A NAME="SEC34" HREF="qemu-doc.html#TOC34">3.10.3.1 CPU usage reduction</A></H4>
<P>
DOS does not correctly use the CPU HLT instruction. The result is that
-<H1><A NAME="SEC33" HREF="qemu-doc.html#TOC33">4. QEMU PowerPC System emulator invocation</A></H1>
+<H1><A NAME="SEC35" HREF="qemu-doc.html#TOC35">4. QEMU PowerPC System emulator invocation</A></H1>
<P>
Use the executable <TT>`qemu-system-ppc'</TT> to simulate a complete PREP
-<H1><A NAME="SEC34" HREF="qemu-doc.html#TOC34">5. Sparc32 System emulator invocation</A></H1>
+<H1><A NAME="SEC36" HREF="qemu-doc.html#TOC36">5. Sparc32 System emulator invocation</A></H1>
<P>
Use the executable <TT>`qemu-system-sparc'</TT> to simulate a JavaStation
-<H1><A NAME="SEC35" HREF="qemu-doc.html#TOC35">6. Sparc64 System emulator invocation</A></H1>
+<H1><A NAME="SEC37" HREF="qemu-doc.html#TOC37">6. Sparc64 System emulator invocation</A></H1>
<P>
Use the executable <TT>`qemu-system-sparc64'</TT> to simulate a Sun4u machine.
-<H1><A NAME="SEC36" HREF="qemu-doc.html#TOC36">7. MIPS System emulator invocation</A></H1>
+<H1><A NAME="SEC38" HREF="qemu-doc.html#TOC38">7. MIPS System emulator invocation</A></H1>
<P>
Use the executable <TT>`qemu-system-mips'</TT> to simulate a MIPS machine.
-<H1><A NAME="SEC37" HREF="qemu-doc.html#TOC37">8. QEMU User space emulator invocation</A></H1>
+<H1><A NAME="SEC39" HREF="qemu-doc.html#TOC39">8. QEMU User space emulator invocation</A></H1>
-<H2><A NAME="SEC38" HREF="qemu-doc.html#TOC38">8.1 Quick Start</A></H2>
+<H2><A NAME="SEC40" HREF="qemu-doc.html#TOC40">8.1 Quick Start</A></H2>
<P>
In order to launch a Linux process, QEMU needs the process executable
-<H2><A NAME="SEC39" HREF="qemu-doc.html#TOC39">8.2 Wine launch</A></H2>
+<H2><A NAME="SEC41" HREF="qemu-doc.html#TOC41">8.2 Wine launch</A></H2>
<UL>
-<H2><A NAME="SEC40" HREF="qemu-doc.html#TOC40">8.3 Command line options</A></H2>
+<H2><A NAME="SEC42" HREF="qemu-doc.html#TOC42">8.3 Command line options</A></H2>
<PRE>
-<H1><A NAME="SEC41" HREF="qemu-doc.html#TOC41">9. Compilation from the sources</A></H1>
+<H1><A NAME="SEC43" HREF="qemu-doc.html#TOC43">9. Compilation from the sources</A></H1>
-<H2><A NAME="SEC42" HREF="qemu-doc.html#TOC42">9.1 Linux/Unix</A></H2>
+<H2><A NAME="SEC44" HREF="qemu-doc.html#TOC44">9.1 Linux/Unix</A></H2>
-<H3><A NAME="SEC43" HREF="qemu-doc.html#TOC43">9.1.1 Compilation</A></H3>
+<H3><A NAME="SEC45" HREF="qemu-doc.html#TOC45">9.1.1 Compilation</A></H3>
<P>
First you must decompress the sources:
-<H3><A NAME="SEC44" HREF="qemu-doc.html#TOC44">9.1.2 Tested tool versions</A></H3>
+<H3><A NAME="SEC46" HREF="qemu-doc.html#TOC46">9.1.2 Tested tool versions</A></H3>
<P>
In order to compile QEMU succesfully, it is very important that you
-<H2><A NAME="SEC45" HREF="qemu-doc.html#TOC45">9.2 Windows</A></H2>
+<H2><A NAME="SEC47" HREF="qemu-doc.html#TOC47">9.2 Windows</A></H2>
<UL>
-<H2><A NAME="SEC46" HREF="qemu-doc.html#TOC46">9.3 Cross compilation for Windows with Linux</A></H2>
+<H2><A NAME="SEC48" HREF="qemu-doc.html#TOC48">9.3 Cross compilation for Windows with Linux</A></H2>
<UL>
-<H2><A NAME="SEC47" HREF="qemu-doc.html#TOC47">9.4 Mac OS X</A></H2>
+<H2><A NAME="SEC49" HREF="qemu-doc.html#TOC49">9.4 Mac OS X</A></H2>
<P>
The Mac OS X patches are not fully merged in QEMU, so you should look
<P><HR><P>
-This document was generated on 24 July 2005 using
+This document was generated on 4 September 2005 using
<A HREF="http://wwwinfo.cern.ch/dis/texi2html/">texi2html</A> 1.56k.
</BODY>
</HTML>
Linux should boot and give you a prompt.
+@node sec_invocation
@section Invocation
@example
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
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
.\" ========================================================================
.\"
.IX Title "QEMU-IMG 1"
-.TH QEMU-IMG 1 "2005-07-24" " " " "
+.TH QEMU-IMG 1 "2005-09-04" " " " "
.SH "NAME"
qemu\-img \- QEMU disk image utility
.SH "SYNOPSIS"
<HTML>
<HEAD>
-<!-- Created by texi2html 1.56k from qemu-tech.texi on 24 July 2005 -->
+<!-- Created by texi2html 1.56k from qemu-tech.texi on 4 September 2005 -->
<TITLE>QEMU Internals</TITLE>
</HEAD>
<P>
Example of usage of <CODE>libqemu</CODE> to emulate a user mode i386 CPU.
<P><HR><P>
-This document was generated on 24 July 2005 using
+This document was generated on 4 September 2005 using
<A HREF="http://wwwinfo.cern.ch/dis/texi2html/">texi2html</A> 1.56k.
</BODY>
</HTML>
.\" ========================================================================
.\"
.IX Title "QEMU 1"
-.TH QEMU 1 "2005-07-24" " " " "
+.TH QEMU 1 "2005-09-04" " " " "
.SH "NAME"
qemu \- QEMU System Emulator
.SH "SYNOPSIS"
.Sp
Note that a \s-1SAMBA\s0 server must be installed on the host \s-1OS\s0 in
\&\fI/usr/sbin/smbd\fR. \s-1QEMU\s0 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.
.IP "\fB\-redir [tcp|udp]:host\-port:[guest\-host]:guest\-port\fR" 4
.IX Item "-redir [tcp|udp]:host-port:[guest-host]:guest-port"
When using the user mode network stack, redirect incoming \s-1TCP\s0 or \s-1UDP\s0
* 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;
}
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];
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
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;
#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
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
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);
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)
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
}
break;
case 0x131: /* rdtsc */
+ gen_jmp_im(pc_start - s->cs_base);
gen_op_rdtsc();
break;
case 0x134: /* sysenter */
qemu_get_clock(rt_clock))) {
/* stop the cpu because a timer occured */
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
+#ifdef USE_KQEMU
+ if (global_env->kqemu_enabled) {
+ kqemu_cpu_interrupt(global_env);
+ }
+#endif
}
}
#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)
{
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)
void readline_start(const char *prompt, int is_password,
ReadLineFunc *readline_func, void *opaque);
+void kqemu_record_dump(void);
+
#endif /* VL_H */