[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[qvm86-devel] [patch] QVM86 / KQEMU for Windows updates
From: |
Filip Navara |
Subject: |
[qvm86-devel] [patch] QVM86 / KQEMU for Windows updates |
Date: |
Thu, 28 Jul 2005 13:23:41 +0200 |
User-agent: |
Mozilla Thunderbird 0.9 (Windows/20041103) |
Changes:
- Implement the "scheduling" functions.
- Fix a bug which cause the driver to fail unloading on Win2K machines.
- Attempt to fix QVM86 on machines with NX support.
- Installation script.
Index: exec-all.h
===================================================================
RCS file: /cvsroot/qemu/qemu/exec-all.h,v
retrieving revision 1.34
diff -u -p -r1.34 exec-all.h
--- exec-all.h 24 Jul 2005 14:14:53 -0000 1.34
+++ exec-all.h 27 Jul 2005 20:53:43 -0000
@@ -607,6 +607,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_cpu_interrupt(CPUState *env);
static inline int kqemu_is_ok(CPUState *env)
{
Index: kqemu.c
===================================================================
RCS file: /cvsroot/qemu/qemu/kqemu.c,v
retrieving revision 1.4
diff -u -p -r1.4 kqemu.c
--- kqemu.c 24 Apr 2005 18:03:37 -0000 1.4
+++ kqemu.c 27 Jul 2005 20:53:24 -0000
@@ -456,11 +456,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);
@@ -544,6 +547,15 @@ int kqemu_cpu_exec(CPUState *env)
exit(1);
}
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
Index: vl.c
===================================================================
RCS file: /cvsroot/qemu/qemu/vl.c,v
retrieving revision 1.133
diff -u -p -r1.133 vl.c
--- vl.c 24 Jul 2005 18:44:55 -0000 1.133
+++ vl.c 27 Jul 2005 20:54:26 -0000
@@ -875,6 +875,9 @@ static void host_alarm_handler(int host_
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
}
}
--- kqemu/kqemu-doc.html Sun Jul 24 20:02:14 2005
+++ kqemu/kqemu-doc.html Wed Jul 27 23:20:28 2005
@@ -173,16 +173,7 @@ the option <CODE>major=N</CODE> to set a
<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>
In order to start kqemu, you must do:
--- kqemu/kqemu-doc.texi Sun Jul 24 20:02:12 2005
+++ kqemu/kqemu-doc.texi Wed Jul 27 23:19:38 2005
@@ -112,13 +112,7 @@ the option @code{major=N} to set an alte
@section QEMU Accelerator Installation for Windows
-Copy the kqemu driver @file{kqemu.sys} to
address@hidden:\winnt\system32\drivers}. Then do:
address@hidden
-regedit kqemu.reg
address@hidden example
-
-Now kqemu is installed and you must restart your system.
+Right click on @file{kqemu.inf} in Explorer and choose Install.
In order to start kqemu, you must do:
@example
--- kqemu/kqemu-win32.c Sun Jul 24 19:39:55 2005
+++ kqemu/kqemu-win32.c Thu Jul 28 13:09:45 2005
@@ -36,6 +36,14 @@ typedef unsigned long long uint64_t;
/* 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,
@@ -57,6 +65,7 @@ struct kqemu_user_page *CDECL kqemu_lock
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;
@@ -150,19 +159,19 @@ void CDECL kqemu_io_unmap(void *ptr, uns
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)
@@ -256,12 +265,19 @@ KQemuDeviceControl(PDEVICE_OBJECT Device
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;
}
@@ -294,6 +310,10 @@ KQemuDeviceControl(PDEVICE_OBJECT Device
VOID STDCALL
KQemuUnload(PDRIVER_OBJECT DriverObject)
{
+ UNICODE_STRING SymlinkName;
+
+ RtlInitUnicodeString(&SymlinkName, L"\\??\\kqemu");
+ IoDeleteSymbolicLink(&SymlinkName);
IoDeleteDevice(DriverObject->DeviceObject);
}
@@ -312,6 +332,8 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
MmLockPagableCodeSection(DriverEntry);
+ ExInitializeFastMutex(&instance_lock);
+
DriverObject->MajorFunction[IRP_MJ_CREATE] = KQemuCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KQemuClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KQemuDeviceControl;
@@ -324,10 +346,17 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
&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/kqemu.h Sun Jul 24 19:38:27 2005
+++ kqemu/kqemu.h Wed Jul 27 23:07:48 2005
@@ -1,7 +1,7 @@
#ifndef KQEMU_H
#define KQEMU_H
-#define KQEMU_VERSION 0x010100
+#define KQEMU_VERSION 0x010101
struct kqemu_segment_cache {
uint32_t selector;
Index: ChangeLog
===================================================================
RCS file: /cvsroot/qvm86/qvm86/ChangeLog,v
retrieving revision 1.20
diff -u -p -r1.20 ChangeLog
--- ChangeLog 18 Jun 2005 22:59:47 -0000 1.20
+++ ChangeLog 28 Jul 2005 11:14:05 -0000
@@ -1,3 +1,11 @@
+2005-07-28 Filip Navara <address@hidden>
+
+ * qvm86-win32.c (KQemuUnload): Correctly delete symlink on
+ driver unload.
+ (host_do_sched): Implement.
+ (host_alloc_pages, host_free_pages): Experimental fix for machines
+ with NX support.
+
2005-06-18 Paul Brook <address@hidden>
* qvm86-host.c (rdtsc): Move inside #ifdef QVM86_PROFILE.
@@ -6,7 +14,7 @@
(qvm86_clear_gdt_entries): New function.
(qvm86_setup_monitor_idt): Return immediately if nothing to do.
(qvm86_shadow_fault): Update comments.
- (qvm86_handle_exception): Remove debugging code. Contuinue execution
+ (qvm86_handle_exception): Remove debugging code. Continue execution
after a hardware interrupt when possible. Use new gdt clearing code.
* qvm86-linux.c (host_do_sched): New function.
* qvm86-win32.c (host_do_sched): New function.
Index: README
===================================================================
RCS file: /cvsroot/qvm86/qvm86/README,v
retrieving revision 1.5
diff -u -p -r1.5 README
--- README 10 Apr 2005 10:48:14 -0000 1.5
+++ README 28 Jul 2005 11:11:12 -0000
@@ -26,11 +26,11 @@ can find it. You need to manually load
QVM86 uses a dynamic misc device minor. If you are using devfs or udev then
/dev/qvm86 should be created automatically when you load the module.
-On Windows hosts you need to copy qvm86.sys to windows/system32/drivers, apply
-qvm86.reg and do "net start qvm86". Windows host support is extremely
-experimental. The windows code has been built with the mingw32 toolchains.
-It is possible to compile on cygwin, but some hacking of makefiles is
-required to ensure -mno-cygwin is used.
+On Windows hosts you right click on qvm86.inf and choose Install and then
+do "net start qvm86". Windows host support is extremely experimental.
+The windows code has been built with the mingw32 toolchains. It is possible
+to compile on cygwin, but some hacking of makefiles is required to ensure
+-mno-cygwin is used.
WARNING: QVM86 is still in the early stages of development.
It may crash your machine or cause data corruption. Do NOT use it on any
Index: kqemu.h
===================================================================
RCS file: /cvsroot/qvm86/qvm86/kqemu.h,v
retrieving revision 1.3
diff -u -p -r1.3 kqemu.h
--- kqemu.h 9 Apr 2005 23:32:54 -0000 1.3
+++ kqemu.h 28 Jul 2005 11:13:21 -0000
@@ -1,7 +1,11 @@
#ifndef KQEMU_H
#define KQEMU_H
+#ifdef _WIN32
+#define KQEMU_VERSION 0x010101
+#else
#define KQEMU_VERSION 0x010000
+#endif
struct kqemu_segment_cache {
uint32_t selector;
Index: qvm86-host.c
===================================================================
RCS file: /cvsroot/qvm86/qvm86/qvm86-host.c,v
retrieving revision 1.11
diff -u -p -r1.11 qvm86-host.c
--- qvm86-host.c 18 Jun 2005 22:59:47 -0000 1.11
+++ qvm86-host.c 22 Jul 2005 12:47:42 -0000
@@ -832,7 +832,7 @@ qvm86_handle_exception (qvm86_state * qs
soft_int (vector);
/* Return to userspace if there are signals pending, otherwise
resume guest execution. */
- if (host_do_sched())
+ if (host_do_sched(qs))
return 2;
else
return 0;
Index: qvm86-linux.c
===================================================================
RCS file: /cvsroot/qvm86/qvm86/qvm86-linux.c,v
retrieving revision 1.5
diff -u -p -r1.5 qvm86-linux.c
--- qvm86-linux.c 18 Jun 2005 22:59:47 -0000 1.5
+++ qvm86-linux.c 22 Jul 2005 12:47:35 -0000
@@ -67,7 +67,7 @@ MODULE_LICENSE("GPL");
/* Give other tasks a chance to run. Returns nonzero if this task has
signals pending. */
int
-host_do_sched()
+host_do_sched (qvm86_state *qs)
{
if (need_resched())
schedule();
Index: qvm86-win32.c
===================================================================
RCS file: /cvsroot/qvm86/qvm86/qvm86-win32.c,v
retrieving revision 1.4
diff -u -p -r1.4 qvm86-win32.c
--- qvm86-win32.c 18 Jun 2005 22:59:47 -0000 1.4
+++ qvm86-win32.c 28 Jul 2005 11:07:24 -0000
@@ -22,15 +22,38 @@
#include "qvm86.h"
-/* Give other tasks a chance to run. Returns nonzero if this task has
- signals pending. */
int
-host_do_sched()
+host_do_sched(qvm86_state *State)
{
- /* See the linux implementation for how this should work. I've no idea
- what the equivalent windows code is. Always returning 1 is safe but
- probably not optimal. */
- return 1;
+ PIRP Irp = State->host_opaque;
+
+ /*
+ * The Linux version of this routines does two things:
+ * 1. Reschedules if other task is pending.
+ * 2. Returns 1 if some signal pending, 0 otherwise.
+ *
+ * There is no need to do anything on Windows NT to manually
+ * reschedule threads since they can be scheduled at any time
+ * by the OS even if they're currently in kernel mode (unless
+ * we're running at IRQL >= DISPATCH_LEVEL of course, which is
+ * not our case).
+ *
+ * As for point 2. we're in kind of uneasy situation since there
+ * is no direct equivalent of POSIX signals on Windows. The two
+ * closest things would be APCs and SEH, neither of which make
+ * sense in this context. To implement this functionality I decided
+ * to take another road ... the ultimate effect of returning 1
+ * from this routine is that the control is passed back to the OS
+ * and the I/O request packet (IRP) is completed. There are only
+ * cases of interruption that we really need to handle. The first one
+ * is thread termination which has the effect of marking all IRPs
+ * as cancelled and waiting for them to be completed, so all we do
+ * here is to return 1 if the IRP was marked as cancelled. The
+ * second one is when QEMU timer is fired. We use a helper code in
+ * the main program to cancel the IRP in that case.
+ */
+
+ return Irp->Cancel;
}
void *
@@ -50,7 +73,18 @@ host_alloc_pages(int count)
{
char * ptr;
- ptr = MmAllocateNonCachedMemory(PAGE_SIZE * count);
+ /*
+ * Implementation note: We don't use MmAllocateNonCachedMemory here
+ * since it returns pages with the NX bit set. All Microsoft
+ * documentation seems to suggest that memory allocated from
+ * non-paged pool shouldn't have the bit set, but so far I have
+ * no proof if it's true or not. If it isn't, we would have to
+ * resort to much more invasive and dangerous techniques such as
+ * allocation user mode pages with NtAllocateVirtualMemory.
+ */
+
+ ptr = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * count,
+ TAG('Q','V','M','P'));
if (!ptr)
return NULL;
RtlZeroMemory(ptr, PAGE_SIZE * count);
@@ -70,7 +104,7 @@ host_free_pages(void *ptr, int count)
{
if (!ptr)
return;
- MmFreeNonCachedMemory(ptr, PAGE_SIZE * count);
+ ExFreePool(ptr);
}
unsigned long
@@ -105,6 +139,7 @@ host_map_user(unsigned long useraddr, qv
mdl_pages = (PPFN_NUMBER)(mdl + 1);
MmInitializeMdl(mdl, useraddr, PAGE_SIZE);
+ /* XXX: Protect with SEH. */
MmProbeAndLockPages(mdl, KernelMode, IoModifyAccess);
map->host = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
@@ -219,12 +254,26 @@ KQemuDeviceControl(PDEVICE_OBJECT Device
break;
}
+ /*
+ * We allow only one KQEMU_EXEC request at a time and use
+ * the host_opaque pointer to store the IRP location. It
+ * is later used in host_do_sched.
+ */
+ if (InterlockedCompareExchangePointer(&State->host_opaque,
+ Irp, NULL) != NULL)
+ {
+ Status = STATUS_DEVICE_NOT_READY;
+ break;
+ }
+
RtlCopyMemory(&s, Irp->AssociatedIrp.SystemBuffer, sizeof(s));
ret = qvm86_exec(State, &s);
s.retval = ret;
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &s, sizeof(s));
Irp->IoStatus.Information = sizeof(s);
Status = STATUS_SUCCESS;
+
+ InterlockedExchangePointer(&State->host_opaque, NULL);
}
break;
@@ -255,6 +304,10 @@ KQemuDeviceControl(PDEVICE_OBJECT Device
VOID STDCALL
KQemuUnload(PDRIVER_OBJECT DriverObject)
{
+ UNICODE_STRING SymlinkName;
+
+ RtlInitUnicodeString(&SymlinkName, L"\\??\\qvm86");
+ IoDeleteSymbolicLink(&SymlinkName);
IoDeleteDevice(DriverObject->DeviceObject);
}
@@ -288,7 +341,12 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
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;
}
Index: qvm86.h
===================================================================
RCS file: /cvsroot/qvm86/qvm86/qvm86.h,v
retrieving revision 1.4
diff -u -p -r1.4 qvm86.h
--- qvm86.h 18 Jun 2005 22:59:47 -0000 1.4
+++ qvm86.h 22 Jul 2005 12:47:23 -0000
@@ -244,6 +244,9 @@ typedef struct
/* This will be nonzero if a fatal error occured. Usually due to
something not yet implemented. Ideally this would never happen. */
int die;
+
+ /* This pointer is exclusively for use by specific host code. */
+ void *host_opaque;
} qvm86_state;
void qvm86_init (qvm86_state * qs, struct kqemu_init * init);
@@ -252,7 +255,7 @@ void qvm86_init_device (qvm86_state *);
void qvm86_cleanup_device (qvm86_state *);
/* Give other tasks a chance to run. Returns nonzero if this task has
signals pending. */
-int host_do_sched(void);
+int host_do_sched (qvm86_state *);
/* Allocate a contiguous block of physical memory. The returned block must
be suitable for use with host_phys_addr. */
void * host_alloc_pages (int);
Index: qvm86.reg
===================================================================
RCS file: /cvsroot/qvm86/qvm86/qvm86.reg,v
retrieving revision 1.1
diff -u -p -r1.1 qvm86.reg
--- qvm86.reg 9 Apr 2005 23:32:54 -0000 1.1
+++ /dev/null 28 Jul 2005 11:10:07 -0000
@@ -1,7 +0,0 @@
-REGEDIT4
-
-[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\qvm86]
-"Type"=dword:00000001
-"Start"=dword:00000003
-"ErrorControl"=dword:00000001
-"DisplayName"="qvm86"
- [qvm86-devel] [patch] QVM86 / KQEMU for Windows updates,
Filip Navara <=