Initial import of kqemu-1.4.0pre1
[kqemu.git] / kqemu-win32.c
blob9eb096a397d6ad33c8579390a6a293d18cf9e4a0
1 /*
2 * Windows NT kernel wrapper for KQEMU
4 * Copyright (C) 2005 Filip Navara
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include <stddef.h>
25 #include <ddk/ntddk.h>
27 typedef unsigned char uint8_t;
28 typedef unsigned short uint16_t;
29 typedef int int32_t;
30 typedef unsigned int uint32_t;
31 typedef unsigned long long uint64_t;
33 #undef CDECL
34 #include "kqemu-kernel.h"
36 /* XXX: make it dynamic according to available RAM */
37 #define MAX_LOCKED_PAGES (16386 / 4)
39 struct kqemu_instance {
40 struct kqemu_state *state;
41 PIRP current_irp;
44 FAST_MUTEX instance_lock;
45 struct kqemu_instance *active_instance;
46 struct kqemu_global_state *kqemu_gs;
48 /* lock the page at virtual address 'user_addr' and return its
49 page index. Return -1 if error */
50 struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
51 unsigned long user_addr)
53 PMDL mdl;
54 PPFN_NUMBER mdl_pages;
56 if (user_addr & 0xfff) {
57 DbgPrint("kqemu: unaligned user memory\n");
58 return NULL;
61 mdl = ExAllocatePool(NonPagedPool, sizeof(MDL) + sizeof(PFN_NUMBER));
62 if (mdl == NULL) {
63 DbgPrint("kqemu: Not enough memory for MDL structure\n");
64 return NULL;
66 mdl_pages = (PPFN_NUMBER)(mdl + 1);
68 MmInitializeMdl(mdl, user_addr, PAGE_SIZE);
69 /* XXX: Protect with SEH. */
70 MmProbeAndLockPages(mdl, KernelMode, IoModifyAccess);
71 *ppage_index = mdl_pages[0];
72 return (struct kqemu_user_page *)mdl;
75 void CDECL kqemu_unlock_user_page(struct kqemu_user_page *page)
77 PMDL mdl = (PMDL)page;
79 MmUnlockPages(mdl);
80 ExFreePool(mdl);
83 struct kqemu_page *CDECL kqemu_alloc_zeroed_page(unsigned long *ppage_index)
85 void *ptr;
86 LARGE_INTEGER pa;
88 ptr = MmAllocateNonCachedMemory(PAGE_SIZE);
89 if (!ptr)
90 return NULL;
91 RtlZeroMemory(ptr, PAGE_SIZE);
92 pa = MmGetPhysicalAddress(ptr);
93 *ppage_index = (unsigned long)(pa.QuadPart >> PAGE_SHIFT);
94 return (struct kqemu_page *)ptr;
97 void CDECL kqemu_free_page(struct kqemu_page *page)
99 void *ptr = page;
101 if (!ptr)
102 return;
103 MmFreeNonCachedMemory(ptr, PAGE_SIZE);
106 void * CDECL kqemu_page_kaddr(struct kqemu_page *page)
108 void *ptr = page;
109 return ptr;
112 void * CDECL kqemu_vmalloc(unsigned int size)
114 void * ptr;
116 ptr = ExAllocatePoolWithTag(NonPagedPool, size, TAG('K','Q','M','U'));
117 if (!ptr)
118 return NULL;
119 RtlZeroMemory(ptr, size);
120 return ptr;
123 void CDECL kqemu_vfree(void *ptr)
125 if (!ptr)
126 return;
127 ExFreePool(ptr);
130 unsigned long CDECL kqemu_vmalloc_to_phys(const void *vaddr)
132 LARGE_INTEGER pa;
134 pa = MmGetPhysicalAddress((void *)vaddr);
135 return (unsigned long)(pa.QuadPart >> PAGE_SHIFT);
138 /* Map a IO area in the kernel address space and return its
139 address. Return NULL if error or not implemented. */
140 void * CDECL kqemu_io_map(unsigned long page_index, unsigned int size)
142 #if 1
143 PHYSICAL_ADDRESS pa;
145 pa.QuadPart = page_index << PAGE_SHIFT;
146 return MmMapIoSpace(pa, size, MmNonCached);
147 #else
148 /* XXX: mingw32 tools too old */
149 return NULL;
150 #endif
153 /* Unmap the IO area */
154 void CDECL kqemu_io_unmap(void *ptr, unsigned int size)
156 return MmUnmapIoSpace(ptr, size);
159 /* return TRUE if a signal is pending (i.e. the guest must stop
160 execution) */
161 int CDECL kqemu_schedule(void)
163 #if 0
164 return active_instance->current_irp->Cancel;
165 #else
166 /* XXX: temporary "fix" to correct the CancelIO() problem. A
167 proper solution may be to add a new KQEMU_INTERRUPT ioctl. */
168 return TRUE;
169 #endif
172 void CDECL kqemu_log(const char *fmt, ...)
174 char log_buf[1024];
175 va_list ap;
177 va_start(ap, fmt);
178 _vsnprintf(log_buf, sizeof(log_buf), fmt, ap);
179 DbgPrint("kqemu: %s", log_buf);
180 va_end(ap);
183 NTSTATUS STDCALL
184 KQemuCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
186 PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
187 struct kqemu_instance *State;
189 State = kqemu_vmalloc(sizeof(struct kqemu_instance));
190 if (State == NULL)
192 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
193 Irp->IoStatus.Information = 0;
194 IoCompleteRequest(Irp, IO_NO_INCREMENT);
195 return STATUS_INSUFFICIENT_RESOURCES;
198 IrpStack->FileObject->FsContext = State;
200 Irp->IoStatus.Status = STATUS_SUCCESS;
201 Irp->IoStatus.Information = 0;
202 IoCompleteRequest(Irp, IO_NO_INCREMENT);
204 return STATUS_SUCCESS;
207 NTSTATUS STDCALL
208 KQemuClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
210 PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
211 struct kqemu_instance *State = IrpStack->FileObject->FsContext;
213 if (State->state) {
214 kqemu_delete(State->state);
215 State->state = NULL;
217 kqemu_vfree(State);
219 Irp->IoStatus.Status = STATUS_SUCCESS;
220 Irp->IoStatus.Information = 0;
221 IoCompleteRequest(Irp, IO_NO_INCREMENT);
223 return STATUS_SUCCESS;
226 NTSTATUS STDCALL
227 KQemuDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
229 PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
230 struct kqemu_instance *State = IrpStack->FileObject->FsContext;
231 NTSTATUS Status;
232 int ret;
234 Irp->IoStatus.Information = 0;
236 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
238 case KQEMU_INIT:
239 if (State->state) {
240 Status = STATUS_INVALID_PARAMETER;
241 break;
243 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
244 sizeof(struct kqemu_init))
246 Status = STATUS_INVALID_PARAMETER;
247 break;
249 State->state = kqemu_init((struct kqemu_init *)Irp->AssociatedIrp.SystemBuffer,
250 kqemu_gs);
251 if (!State->state) {
252 Status = STATUS_INSUFFICIENT_RESOURCES;
253 break;
255 Status = STATUS_SUCCESS;
256 break;
258 case KQEMU_EXEC:
260 struct kqemu_cpu_state *ctx;
262 if (!State->state) {
263 Status = STATUS_INVALID_PARAMETER;
264 break;
266 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
267 sizeof(*ctx) ||
268 IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
269 sizeof(*ctx))
271 Status = STATUS_INVALID_PARAMETER;
272 break;
275 ExAcquireFastMutex(&instance_lock);
276 active_instance = State;
277 State->current_irp = Irp;
279 ctx = kqemu_get_cpu_state(State->state);
281 RtlCopyMemory(ctx, Irp->AssociatedIrp.SystemBuffer,
282 sizeof(*ctx));
283 ret = kqemu_exec(State->state);
284 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, ctx, sizeof(*ctx));
286 ExReleaseFastMutex(&instance_lock);
288 Irp->IoStatus.Information = sizeof(*ctx);
289 Status = STATUS_SUCCESS;
291 break;
293 case KQEMU_SET_PHYS_MEM:
295 struct kqemu_phys_mem *kphys_mem;
297 if (!State->state) {
298 Status = STATUS_INVALID_PARAMETER;
299 break;
301 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
302 sizeof(struct kqemu_phys_mem))
304 Status = STATUS_INVALID_PARAMETER;
305 break;
308 ExAcquireFastMutex(&instance_lock);
310 kphys_mem = (struct kqemu_phys_mem *)Irp->AssociatedIrp.SystemBuffer;
311 ret = kqemu_set_phys_mem(State->state, kphys_mem);
313 ExReleaseFastMutex(&instance_lock);
315 if (ret == 0)
316 Status = STATUS_SUCCESS;
317 else
318 Status = STATUS_INVALID_PARAMETER;
320 break;
322 case KQEMU_GET_VERSION:
323 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
324 sizeof(int))
326 Status = STATUS_INVALID_PARAMETER;
327 break;
330 *((int *)Irp->AssociatedIrp.SystemBuffer) = KQEMU_VERSION;
331 Irp->IoStatus.Information = sizeof(int);
332 Status = STATUS_SUCCESS;
333 break;
335 default:
336 Status = STATUS_INVALID_PARAMETER;
337 break;
340 Irp->IoStatus.Status = Status;
341 IoCompleteRequest(Irp, IO_NO_INCREMENT);
343 return Status;
346 VOID STDCALL
347 KQemuUnload(PDRIVER_OBJECT DriverObject)
349 UNICODE_STRING SymlinkName;
351 RtlInitUnicodeString(&SymlinkName, L"\\??\\kqemu");
352 IoDeleteSymbolicLink(&SymlinkName);
353 IoDeleteDevice(DriverObject->DeviceObject);
354 if (kqemu_gs) {
355 kqemu_global_delete(kqemu_gs);
356 kqemu_gs = NULL;
360 NTSTATUS STDCALL
361 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
363 PDEVICE_OBJECT DeviceObject;
364 UNICODE_STRING DeviceName;
365 UNICODE_STRING SymlinkName;
366 NTSTATUS Status;
368 DbgPrint("QEMU Accelerator Module version %d.%d.%d\n",
369 (KQEMU_VERSION >> 16),
370 (KQEMU_VERSION >> 8) & 0xff,
371 (KQEMU_VERSION) & 0xff);
373 MmLockPagableCodeSection(DriverEntry);
375 ExInitializeFastMutex(&instance_lock);
377 kqemu_gs = kqemu_global_init(MAX_LOCKED_PAGES);
379 DriverObject->MajorFunction[IRP_MJ_CREATE] = KQemuCreate;
380 DriverObject->MajorFunction[IRP_MJ_CLOSE] = KQemuClose;
381 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KQemuDeviceControl;
382 DriverObject->DriverUnload = KQemuUnload;
384 RtlInitUnicodeString(&DeviceName, L"\\Device\\kqemu");
385 RtlInitUnicodeString(&SymlinkName, L"\\??\\kqemu");
387 Status = IoCreateDevice(DriverObject, 0,
388 &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE,
389 &DeviceObject);
390 if (!NT_SUCCESS(Status))
392 return Status;
395 /* Create the dos device link */
396 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
397 if (!NT_SUCCESS(Status))
399 IoDeleteDevice(DeviceObject);
400 return Status;
403 return STATUS_SUCCESS;