VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxGuest/VBoxGuest.cpp@ 4145

Last change on this file since 4145 was 4145, checked in by vboxsync, 17 years ago

Never (!!) put the isr handler in pagable memory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.7 KB
Line 
1/** @file
2 *
3 * VBoxGuest -- VirtualBox Win32 guest support driver
4 *
5 * Copyright (C) 2006-2007 innotek GmbH
6 *
7 * This file is part of VirtualBox Open Source Edition (OSE), as
8 * available from http://www.virtualbox.org. This file is free software;
9 * you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation,
11 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
12 * distribution. VirtualBox OSE is distributed in the hope that it will
13 * be useful, but WITHOUT ANY WARRANTY of any kind.
14 */
15
16// enable backdoor logging
17//#define LOG_ENABLED
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "VBoxGuest_Internal.h"
23#ifdef TARGET_NT4
24#include "NTLegacy.h"
25#else
26#include "VBoxGuestPnP.h"
27#endif
28#include "Helper.h"
29#include <excpt.h>
30#include <VBox/err.h>
31#include <iprt/assert.h>
32#include <iprt/asm.h>
33#include <stdio.h>
34#include <VBox/VBoxGuestLib.h>
35
36/*******************************************************************************
37* Defined Constants And Macros *
38*******************************************************************************/
39
40
41/*******************************************************************************
42* Internal Functions *
43*******************************************************************************/
44extern "C"
45{
46static NTSTATUS VBoxGuestAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj);
47static void VBoxGuestUnload(PDRIVER_OBJECT pDrvObj);
48static NTSTATUS VBoxGuestCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
49static NTSTATUS VBoxGuestClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
50static NTSTATUS VBoxGuestDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
51static NTSTATUS VBoxGuestSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
52static NTSTATUS VBoxGuestShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp);
53static NTSTATUS VBoxGuestNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
54static VOID vboxWorkerThread(PVOID context);
55static VOID reserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt);
56static VOID vboxIdleThread(PVOID context);
57}
58
59
60/*******************************************************************************
61* Exported Functions *
62*******************************************************************************/
63__BEGIN_DECLS
64ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
65__END_DECLS
66
67#ifdef ALLOC_PRAGMA
68#pragma alloc_text (INIT, DriverEntry)
69#pragma alloc_text (PAGE, createThreads)
70#pragma alloc_text (PAGE, unreserveHypervisorMemory)
71#pragma alloc_text (PAGE, VBoxGuestAddDevice)
72#pragma alloc_text (PAGE, VBoxGuestUnload)
73#pragma alloc_text (PAGE, VBoxGuestCreate)
74#pragma alloc_text (PAGE, VBoxGuestClose)
75#pragma alloc_text (PAGE, VBoxGuestDeviceControl)
76#pragma alloc_text (PAGE, VBoxGuestShutdown)
77#pragma alloc_text (PAGE, VBoxGuestNotSupportedStub)
78/* Note: at least the isr handler should be in non-pagable memory! */
79/*#pragma alloc_text (PAGE, VBoxGuestDpcHandler)
80 #pragma alloc_text (PAGE, VBoxGuestIsrHandler) */
81#pragma alloc_text (PAGE, vboxWorkerThread)
82#pragma alloc_text (PAGE, reserveHypervisorMemory)
83#pragma alloc_text (PAGE, vboxIdleThread)
84#endif
85
86winVersion_t winVersion;
87
88/**
89 * Driver entry point.
90 *
91 * @returns appropriate status code.
92 * @param pDrvObj Pointer to driver object.
93 * @param pRegPath Registry base path.
94 */
95ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
96{
97 NTSTATUS rc = STATUS_SUCCESS;
98
99 dprintf(("VBoxGuest::DriverEntry. Driver built: %s %s\n", __DATE__, __TIME__));
100
101 ULONG majorVersion;
102 ULONG minorVersion;
103 ULONG buildNumber;
104 PsGetVersion(&majorVersion, &minorVersion, &buildNumber, NULL);
105 dprintf(("VBoxGuest::DriverEntry: running on Windows NT version %d.%d, build %d\n", majorVersion, minorVersion, buildNumber));
106 switch (majorVersion)
107 {
108 case 6:
109 winVersion = WINVISTA;
110 break;
111 case 5:
112 switch (minorVersion)
113 {
114 case 2:
115 winVersion = WIN2K3;
116 break;
117 case 1:
118 winVersion = WINXP;
119 break;
120 case 0:
121 winVersion = WIN2K;
122 break;
123 default:
124 dprintf(("VBoxGuest::DriverEntry: unknown version of Windows, refusing!\n"));
125 return STATUS_DRIVER_UNABLE_TO_LOAD;
126 }
127 break;
128 case 4:
129 winVersion = WINNT4;
130 break;
131 default:
132 dprintf(("VBoxGuest::DriverEntry: NT4 required!\n"));
133 return STATUS_DRIVER_UNABLE_TO_LOAD;
134 }
135
136 /*
137 * Setup the driver entry points in pDrvObj.
138 */
139 pDrvObj->DriverUnload = VBoxGuestUnload;
140 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxGuestCreate;
141 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxGuestClose;
142 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxGuestDeviceControl;
143 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxGuestDeviceControl;
144 pDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = VBoxGuestShutdown;
145 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxGuestNotSupportedStub;
146 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxGuestNotSupportedStub;
147#ifdef TARGET_NT4
148 rc = ntCreateDevice(pDrvObj, NULL, pRegPath);
149#else
150 pDrvObj->MajorFunction[IRP_MJ_PNP] = VBoxGuestPnP;
151 pDrvObj->MajorFunction[IRP_MJ_POWER] = VBoxGuestPower;
152 pDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = VBoxGuestSystemControl;
153 pDrvObj->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)VBoxGuestAddDevice;
154#endif
155
156 dprintf(("VBoxGuest::DriverEntry returning %#x\n", rc));
157 return rc;
158}
159
160#ifndef TARGET_NT4
161/**
162 * Handle request from the Plug & Play subsystem
163 *
164 * @returns NT status code
165 * @param pDrvObj Driver object
166 * @param pDevObj Device object
167 */
168static NTSTATUS VBoxGuestAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
169{
170 NTSTATUS rc;
171 dprintf(("VBoxGuest::VBoxGuestAddDevice\n"));
172
173 /*
174 * Create device.
175 */
176 PDEVICE_OBJECT deviceObject = NULL;
177 UNICODE_STRING devName;
178 RtlInitUnicodeString(&devName, VBOXGUEST_DEVICE_NAME_NT);
179 rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXT), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject);
180 if (!NT_SUCCESS(rc))
181 {
182 dprintf(("VBoxGuest::VBoxGuestAddDevice: IoCreateDevice failed with rc=%#x!\n", rc));
183 return rc;
184 }
185 UNICODE_STRING win32Name;
186 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
187 rc = IoCreateSymbolicLink(&win32Name, &devName);
188 if (!NT_SUCCESS(rc))
189 {
190 dprintf(("VBoxGuest::VBoxGuestAddDevice: IoCreateSymbolicLink failed with rc=%#x!\n", rc));
191 IoDeleteDevice(deviceObject);
192 return rc;
193 }
194
195 /*
196 * Setup the device extension.
197 */
198 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)deviceObject->DeviceExtension;
199 RtlZeroMemory(pDevExt, sizeof(VBOXGUESTDEVEXT));
200
201 pDevExt->deviceObject = deviceObject;
202 pDevExt->devState = STOPPED;
203
204 pDevExt->nextLowerDriver = IoAttachDeviceToDeviceStack(deviceObject, pDevObj);
205 if (pDevExt->nextLowerDriver == NULL)
206 {
207 dprintf(("VBoxGuest::VBoxGuestAddDevice: IoAttachDeviceToDeviceStack did not give a nextLowerDrive\n"));
208 IoDeleteSymbolicLink(&win32Name);
209 IoDeleteDevice(deviceObject);
210 return STATUS_DEVICE_NOT_CONNECTED;
211 }
212
213 // driver is ready now
214 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
215
216 dprintf(("VBoxGuest::VBoxGuestAddDevice: returning with rc = 0x%x\n", rc));
217 return rc;
218}
219#endif
220
221
222/**
223 * Unload the driver.
224 *
225 * @param pDrvObj Driver object.
226 */
227void VBoxGuestUnload(PDRIVER_OBJECT pDrvObj)
228{
229 dprintf(("VBoxGuest::VBoxGuestUnload\n"));
230#ifdef TARGET_NT4
231 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDrvObj->DeviceObject->DeviceExtension;
232 unreserveHypervisorMemory(pDevExt);
233 if (pDevExt->workerThread)
234 {
235 dprintf(("VBoxGuest::VBoxGuestUnload: waiting for the worker thread to terminate...\n"));
236 pDevExt->stopThread = TRUE;
237 KeSetEvent(&pDevExt->workerThreadRequest, 0, FALSE);
238 KeWaitForSingleObject(pDevExt->workerThread,
239 Executive, KernelMode, FALSE, NULL);
240 dprintf(("VBoxGuest::VBoxGuestUnload: returned from KeWaitForSingleObject for worker thread\n"));
241 }
242 if (pDevExt->idleThread)
243 {
244 dprintf(("VBoxGuest::VBoxGuestUnload: waiting for the idle thread to terminate...\n"));
245 pDevExt->stopThread = TRUE;
246 KeWaitForSingleObject(pDevExt->idleThread,
247 Executive, KernelMode, FALSE, NULL);
248 dprintf(("VBoxGuest::VBoxGuestUnload: returned from KeWaitForSingleObject for idle thread\n"));
249 }
250
251 hlpVBoxUnmapVMMDevMemory (pDevExt);
252
253 /*
254 * I don't think it's possible to unload a driver which processes have
255 * opened, at least we'll blindly assume that here.
256 */
257 UNICODE_STRING win32Name;
258 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
259 NTSTATUS rc = IoDeleteSymbolicLink(&win32Name);
260 IoDeleteDevice(pDrvObj->DeviceObject);
261#endif
262 dprintf(("VBoxGuest::VBoxGuestUnload: returning\n"));
263}
264
265
266/**
267 * Create (i.e. Open) file entry point.
268 *
269 * @param pDevObj Device object.
270 * @param pIrp Request packet.
271 */
272NTSTATUS VBoxGuestCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
273{
274 dprintf(("VBoxGuest::VBoxGuestCreate\n"));
275
276 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
277 PFILE_OBJECT pFileObj = pStack->FileObject;
278 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
279
280 /*
281 * We are not remotely similar to a directory...
282 * (But this is possible.)
283 */
284 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
285 {
286 dprintf(("VBoxGuest::VBoxGuestCreate: we're not a directory!\n"));
287 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
288 pIrp->IoStatus.Information = 0;
289 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
290 return STATUS_NOT_A_DIRECTORY;
291 }
292
293 NTSTATUS rcNt = pIrp->IoStatus.Status = STATUS_SUCCESS;
294 pIrp->IoStatus.Information = 0;
295 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
296
297 dprintf(("VBoxGuest::VBoxGuestCreate: returning 0x%x\n", rcNt));
298 return rcNt;
299}
300
301
302/**
303 * Close file entry point.
304 *
305 * @param pDevObj Device object.
306 * @param pIrp Request packet.
307 */
308NTSTATUS VBoxGuestClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
309{
310 dprintf(("VBoxGuest::VBoxGuestClose\n"));
311
312 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
313 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
314 PFILE_OBJECT pFileObj = pStack->FileObject;
315 dprintf(("VBoxGuest::VBoxGuestClose: pDevExt=%p pFileObj=%p pSession=%p\n",
316 pDevExt, pFileObj, pFileObj->FsContext));
317
318 pFileObj->FsContext = NULL;
319 pIrp->IoStatus.Information = 0;
320 pIrp->IoStatus.Status = STATUS_SUCCESS;
321 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
322
323 return STATUS_SUCCESS;
324}
325
326#ifdef VBOX_HGCM
327DECLVBGL(void) VBoxHGCMCallback (VMMDevHGCMRequestHeader *pHeader, void *pvData, uint32_t u32Data)
328{
329 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvData;
330
331 dprintf(("VBoxHGCMCallback\n"));
332
333 // this code is subject to "lost wakeup" bug
334 // -- malc
335 while ((pHeader->fu32Flags & VBOX_HGCM_REQ_DONE) == 0)
336 {
337 /* Specifying UserMode so killing the user process will abort the wait. */
338 NTSTATUS rc = KeWaitForSingleObject (&pDevExt->keventNotification, Executive,
339 UserMode, TRUE, NULL /** @todo &timeout? */
340 );
341 dprintf(("VBoxHGCMCallback: Wait returned %d\n", rc));
342
343 if (rc != STATUS_WAIT_0)
344 {
345 dprintf(("VBoxHGCMCallback: The external event was signalled or the wait timed out or terminated.\n"));
346 break;
347 }
348
349 dprintf(("VBoxHGCMCallback: fu32Flags = %08X\n", pHeader->fu32Flags));
350 }
351
352 return;
353}
354
355NTSTATUS vboxHGCMVerifyIOBuffers (PIO_STACK_LOCATION pStack, unsigned cb)
356{
357 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < cb)
358 {
359 dprintf(("VBoxGuest::vboxHGCMVerifyIOBuffers: OutputBufferLength %d < %d\n",
360 pStack->Parameters.DeviceIoControl.OutputBufferLength, cb));
361 return STATUS_INVALID_PARAMETER;
362 }
363
364 if (pStack->Parameters.DeviceIoControl.InputBufferLength < cb)
365 {
366 dprintf(("VBoxGuest::vboxHGCMVerifyIOBuffers: InputBufferLength %d < %d\n",
367 pStack->Parameters.DeviceIoControl.InputBufferLength, cb));
368 return STATUS_INVALID_PARAMETER;
369 }
370
371 return STATUS_SUCCESS;
372}
373
374#endif /* VBOX_HGCM */
375
376static bool
377__declspec (naked) __fastcall
378TestAndClearEvent (PVBOXGUESTDEVEXT pDevExt, int iBitOffset)
379{
380 _asm {
381 lock btr PVBOXGUESTDEVEXT[ecx].u32Events, edx;
382 setc al;
383 movzx eax, al;
384 ret;
385 }
386}
387
388static bool IsPowerOfTwo (uint32_t val)
389{
390 return (val & (val - 1)) == 0;
391}
392
393static int __declspec (naked) __fastcall GetMsb32 (uint32_t val)
394{
395 _asm {
396 bsf eax, ecx;
397 ret;
398 }
399}
400
401static bool CtlGuestFilterMask (uint32_t u32OrMask, uint32_t u32NotMask)
402{
403 bool result = false;
404 VMMDevCtlGuestFilterMask *req;
405 int rc = VbglGRAlloc ((VMMDevRequestHeader **) &req, sizeof (*req),
406 VMMDevReq_CtlGuestFilterMask);
407
408 if (VBOX_SUCCESS (rc))
409 {
410 req->u32OrMask = u32OrMask;
411 req->u32NotMask = u32NotMask;
412
413 rc = VbglGRPerform (&req->header);
414 if (VBOX_FAILURE (rc) || VBOX_FAILURE (req->header.rc))
415 {
416 dprintf (("VBoxGuest::VBoxGuestDeviceControl: error issuing request to VMMDev! "
417 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
418 }
419 else
420 {
421 result = true;
422 }
423 VbglGRFree (&req->header);
424 }
425
426 return result;
427}
428
429/**
430 * Device I/O Control entry point.
431 *
432 * @param pDevObj Device object.
433 * @param pIrp Request packet.
434 */
435NTSTATUS VBoxGuestDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
436{
437 dprintf(("VBoxGuest::VBoxGuestDeviceControl\n"));
438
439 NTSTATUS Status = STATUS_SUCCESS;
440
441 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
442
443 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
444
445 char *pBuf = (char *)pIrp->AssociatedIrp.SystemBuffer; /* all requests are buffered. */
446
447 unsigned cbOut = 0;
448
449 switch (pStack->Parameters.DeviceIoControl.IoControlCode)
450 {
451 case IOCTL_VBOXGUEST_GETVMMDEVPORT:
452 {
453 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_GETVMMDEVPORT\n"));
454
455 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof (VBoxGuestPortInfo))
456 {
457 Status = STATUS_BUFFER_TOO_SMALL;
458 break;
459 }
460
461 VBoxGuestPortInfo *portInfo = (VBoxGuestPortInfo*)pBuf;
462
463 portInfo->portAddress = pDevExt->startPortAddress;
464 portInfo->pVMMDevMemory = pDevExt->pVMMDevMemory;
465
466 cbOut = sizeof(VBoxGuestPortInfo);
467
468 break;
469 }
470
471 case IOCTL_VBOXGUEST_WAITEVENT:
472 {
473 /* Need to be extended to support multiple waiters for an event,
474 * array of counters for each event, event mask is computed, each
475 * time a wait event is arrived.
476 */
477 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_WAITEVENT\n"));
478
479 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VBoxGuestWaitEventInfo))
480 {
481 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d < sizeof(VBoxGuestWaitEventInfo)\n",
482 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestWaitEventInfo)));
483 Status = STATUS_BUFFER_TOO_SMALL;
484 break;
485 }
486
487 if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VBoxGuestWaitEventInfo)) {
488 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < sizeof(VBoxGuestWaitEventInfo)\n",
489 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestWaitEventInfo)));
490 Status = STATUS_BUFFER_TOO_SMALL;
491 break;
492 }
493
494 VBoxGuestWaitEventInfo *eventInfo = (VBoxGuestWaitEventInfo *)pBuf;
495
496 if (!eventInfo->u32EventMaskIn || !IsPowerOfTwo (eventInfo->u32EventMaskIn)) {
497 dprintf (("VBoxGuest::VBoxGuestDeviceControl: Invalid input mask %#x\n",
498 eventInfo->u32EventMaskIn));
499 Status = STATUS_INVALID_PARAMETER;
500 break;
501 }
502
503 eventInfo->u32EventFlagsOut = 0;
504 int iBitOffset = GetMsb32 (eventInfo->u32EventMaskIn);
505
506 dprintf (("mask = %d, iBitOffset = %d\n", iBitOffset, eventInfo->u32EventMaskIn));
507
508 LARGE_INTEGER timeout;
509 timeout.QuadPart = eventInfo->u32TimeoutIn;
510 timeout.QuadPart *= -100000;
511
512 NTSTATUS rc = STATUS_SUCCESS;
513
514 for (;;)
515 {
516 // following code is subject to "lost wakeup" bug
517 // -- malc
518 bool fEventPending = TestAndClearEvent (pDevExt, iBitOffset);
519 if (fEventPending)
520 {
521 eventInfo->u32EventFlagsOut = 1 << iBitOffset;
522 break;
523 }
524
525 rc = KeWaitForSingleObject (&pDevExt->keventNotification, Executive /** @todo UserRequest? */,
526 KernelMode, TRUE,
527 eventInfo->u32TimeoutIn == ~0L ? NULL : &timeout);
528 dprintf(("IOCTL_VBOXGUEST_WAITEVENT: Wait returned %d -> event %x\n", rc, eventInfo->u32EventFlagsOut));
529
530 if (rc != STATUS_SUCCESS)
531 {
532 /* There was a timeout or wait was interrupted, etc. */
533 break;
534 }
535 }
536
537 dprintf (("u32EventFlagsOut = %#x\n", eventInfo->u32EventFlagsOut));
538 cbOut = sizeof(VBoxGuestWaitEventInfo);
539 break;
540 }
541
542 case IOCTL_VBOXGUEST_VMMREQUEST:
543 {
544 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_VMMREQUEST\n"));
545
546#define CHECK_SIZE(s) \
547 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < s) \
548 { \
549 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d < %d\n", \
550 pStack->Parameters.DeviceIoControl.OutputBufferLength, s)); \
551 Status = STATUS_BUFFER_TOO_SMALL; \
552 break; \
553 } \
554 if (pStack->Parameters.DeviceIoControl.InputBufferLength < s) { \
555 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < %d\n", \
556 pStack->Parameters.DeviceIoControl.InputBufferLength, s)); \
557 Status = STATUS_BUFFER_TOO_SMALL; \
558 break; \
559 }
560
561 /* get the request header */
562 CHECK_SIZE(sizeof(VMMDevRequestHeader));
563 VMMDevRequestHeader *requestHeader = (VMMDevRequestHeader *)pBuf;
564 if (!vmmdevGetRequestSize(requestHeader->requestType))
565 {
566 Status = STATUS_INVALID_PARAMETER;
567 break;
568 }
569 /* make sure the buffers suit the request */
570 CHECK_SIZE(vmmdevGetRequestSize(requestHeader->requestType));
571
572 /* just perform the request */
573 VMMDevRequestHeader *req = NULL;
574
575 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, requestHeader->size, requestHeader->requestType);
576
577 if (VBOX_SUCCESS(rc))
578 {
579 /* copy the request information */
580 memcpy((void*)req, (void*)pBuf, requestHeader->size);
581 rc = VbglGRPerform(req);
582
583 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->rc))
584 {
585 dprintf(("VBoxGuest::VBoxGuestDeviceControl IOCTL_VBOXGUEST_VMMREQUEST: error issuing request to VMMDev!"
586 "rc = %d, VMMDev rc = %Vrc\n", rc, req->rc));
587 Status = STATUS_UNSUCCESSFUL;
588 }
589 else
590 {
591 /* copy result */
592 memcpy((void*)pBuf, (void*)req, requestHeader->size);
593 cbOut = requestHeader->size;
594 }
595
596 VbglGRFree(req);
597 }
598 else
599 {
600 Status = STATUS_UNSUCCESSFUL;
601 }
602#undef CHECK_SIZE
603 break;
604 }
605
606 case IOCTL_VBOXGUEST_CTL_FILTER_MASK:
607 {
608 VBoxGuestFilterMaskInfo *maskInfo;
609
610 if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VBoxGuestFilterMaskInfo)) {
611 dprintf (("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < %d\n",
612 pStack->Parameters.DeviceIoControl.InputBufferLength,
613 sizeof (VBoxGuestFilterMaskInfo)));
614 Status = STATUS_BUFFER_TOO_SMALL;
615 break;
616
617 }
618
619 maskInfo = (VBoxGuestFilterMaskInfo *) pBuf;
620 if (!CtlGuestFilterMask (maskInfo->u32OrMask, maskInfo->u32NotMask))
621 {
622 Status = STATUS_UNSUCCESSFUL;
623 }
624 break;
625 }
626
627#ifdef VBOX_HGCM
628 /* HGCM offers blocking IOCTLSs just like waitevent and actually
629 * uses the same waiting code.
630 */
631 case IOCTL_VBOXGUEST_HGCM_CONNECT:
632 {
633 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_HGCM_CONNECT\n"));
634
635 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(VBoxGuestHGCMConnectInfo))
636 {
637 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(VBoxGuestHGCMConnectInfo) %d\n",
638 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestHGCMConnectInfo)));
639 Status = STATUS_INVALID_PARAMETER;
640 break;
641 }
642
643 if (pStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(VBoxGuestHGCMConnectInfo)) {
644 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d != sizeof(VBoxGuestHGCMConnectInfo) %d\n",
645 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestHGCMConnectInfo)));
646 Status = STATUS_INVALID_PARAMETER;
647 break;
648 }
649
650 VBoxGuestHGCMConnectInfo *ptr = (VBoxGuestHGCMConnectInfo *)pBuf;
651
652 /* If request will be processed asynchronously, execution will
653 * go to VBoxHGCMCallback. There it will wait for the request event, signalled from IRQ.
654 * On IRQ arrival, the VBoxHGCMCallback(s) will check the request memory and, if completion
655 * flag is set, returns.
656 */
657
658 dprintf(("a) ptr->u32ClientID = %d\n", ptr->u32ClientID));
659
660 int rc = VbglHGCMConnect (ptr, VBoxHGCMCallback, pDevExt, 0);
661
662 dprintf(("b) ptr->u32ClientID = %d\n", ptr->u32ClientID));
663
664 if (VBOX_FAILURE(rc))
665 {
666 dprintf(("IOCTL_VBOXGUEST_HGCM_CONNECT: vbox rc = %Vrc\n", rc));
667 Status = STATUS_UNSUCCESSFUL;
668 }
669 else
670 {
671 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
672 }
673
674 } break;
675
676 case IOCTL_VBOXGUEST_HGCM_DISCONNECT:
677 {
678 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_HGCM_DISCONNECT\n"));
679
680 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(VBoxGuestHGCMDisconnectInfo))
681 {
682 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(VBoxGuestHGCMDisconnectInfo) %d\n",
683 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestHGCMDisconnectInfo)));
684 Status = STATUS_INVALID_PARAMETER;
685 break;
686 }
687
688 if (pStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(VBoxGuestHGCMDisconnectInfo)) {
689 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d != sizeof(VBoxGuestHGCMDisconnectInfo) %d\n",
690 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestHGCMDisconnectInfo)));
691 Status = STATUS_INVALID_PARAMETER;
692 break;
693 }
694
695 VBoxGuestHGCMDisconnectInfo *ptr = (VBoxGuestHGCMDisconnectInfo *)pBuf;
696
697 /* If request will be processed asynchronously, execution will
698 * go to VBoxHGCMCallback. There it will wait for the request event, signalled from IRQ.
699 * On IRQ arrival, the VBoxHGCMCallback(s) will check the request memory and, if completion
700 * flag is set, returns.
701 */
702
703 int rc = VbglHGCMDisconnect (ptr, VBoxHGCMCallback, pDevExt, 0);
704
705 if (VBOX_FAILURE(rc))
706 {
707 dprintf(("IOCTL_VBOXGUEST_HGCM_DISCONNECT: vbox rc = %Vrc\n", rc));
708 Status = STATUS_UNSUCCESSFUL;
709 }
710 else
711 {
712 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
713 }
714
715 } break;
716
717 case IOCTL_VBOXGUEST_HGCM_CALL:
718 {
719 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_HGCM_CALL\n"));
720
721 Status = vboxHGCMVerifyIOBuffers (pStack,
722 sizeof (VBoxGuestHGCMCallInfo));
723
724 if (Status != STATUS_SUCCESS)
725 {
726 dprintf(("VBoxGuest::VBoxGuestDeviceControl: invalid parameter. Status: %p\n", Status));
727 break;
728 }
729
730 VBoxGuestHGCMCallInfo *ptr = (VBoxGuestHGCMCallInfo *)pBuf;
731
732 int rc = VbglHGCMCall (ptr, VBoxHGCMCallback, pDevExt, 0);
733
734 if (VBOX_FAILURE(rc))
735 {
736 dprintf(("IOCTL_VBOXGUEST_HGCM_CALL: vbox rc = %Vrc\n", rc));
737 Status = STATUS_UNSUCCESSFUL;
738 }
739 else
740 {
741 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
742 }
743
744 } break;
745#endif /* VBOX_HGCM */
746
747 default:
748 Status = STATUS_INVALID_PARAMETER;
749 break;
750 }
751
752 pIrp->IoStatus.Status = Status;
753 pIrp->IoStatus.Information = cbOut;
754
755 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
756
757 dprintf(("VBoxGuest::VBoxGuestDeviceControl: returned cbOut=%d rc=%#x\n", cbOut, Status));
758
759 return Status;
760}
761
762
763/**
764 * IRP_MJ_SYSTEM_CONTROL handler
765 *
766 * @returns NT status code
767 * @param pDevObj Device object.
768 * @param pIrp IRP.
769 */
770NTSTATUS VBoxGuestSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
771{
772 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
773
774 dprintf(("VBoxGuest::VBoxGuestSystemControl\n"));
775
776 /* Always pass it on to the next driver. */
777 IoSkipCurrentIrpStackLocation(pIrp);
778
779 return IoCallDriver(pDevExt->nextLowerDriver, pIrp);
780}
781
782/**
783 * IRP_MJ_SHUTDOWN handler
784 *
785 * @returns NT status code
786 * @param pDevObj Device object.
787 * @param pIrp IRP.
788 */
789NTSTATUS VBoxGuestShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
790{
791 VMMDevPowerStateRequest *req = NULL;
792
793 dprintf(("VBoxGuest::VBoxGuestShutdown\n"));
794
795 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
796
797 if (VBOX_SUCCESS(rc))
798 {
799 req->powerState = VMMDevPowerState_PowerOff;
800
801 rc = VbglGRPerform (&req->header);
802
803 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
804 {
805 dprintf(("VBoxGuest::PowerStateRequest: error performing request to VMMDev."
806 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
807 }
808
809 VbglGRFree (&req->header);
810 }
811
812 return STATUS_SUCCESS;
813}
814
815/**
816 * Stub function for functions we don't implemented.
817 *
818 * @returns STATUS_NOT_SUPPORTED
819 * @param pDevObj Device object.
820 * @param pIrp IRP.
821 */
822NTSTATUS VBoxGuestNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
823{
824 dprintf(("VBoxGuest::VBoxGuestNotSupportedStub\n"));
825 pDevObj = pDevObj;
826
827 pIrp->IoStatus.Information = 0;
828 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
829 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
830
831 return STATUS_NOT_SUPPORTED;
832}
833
834/**
835 * DPC handler
836 *
837 * @param dpc DPC descriptor.
838 * @param pDevObj Device object.
839 * @param irp Interrupt request packet.
840 * @param context Context specific pointer.
841 */
842VOID VBoxGuestDpcHandler(PKDPC dpc, PDEVICE_OBJECT pDevObj,
843 PIRP irp, PVOID context)
844{
845 /* Unblock handlers waiting for arrived events.
846 *
847 * Events are very low things, there is one event flag (1 or more bit)
848 * for each event. Each event is processed by exactly one handler.
849 *
850 * Assume that we trust additions and that other drivers will
851 * handle its respective events without trying to fetch all events.
852 *
853 * Anyway design assures that wrong event processing will affect only guest.
854 *
855 * Event handler calls VMMDev IOCTL for waiting an event.
856 * It supplies event mask. IOCTL blocks on EventNotification.
857 * Here we just signal an the EventNotification to all waiting
858 * threads, the IOCTL handler analyzes events and either
859 * return to caller or blocks again.
860 *
861 * If we do not have too many events this is a simple and good
862 * approach. Other way is to have as many Event objects as the callers
863 * and wake up only callers waiting for the specific event.
864 *
865 * Now with the 'wake up all' appoach we probably do not need the DPC
866 * handler and can signal event directly from ISR.
867 *
868 */
869
870 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
871
872 dprintf(("VBoxGuest::VBoxGuestDpcHandler\n"));
873
874 KePulseEvent(&pDevExt->keventNotification, 0, FALSE);
875
876}
877
878/**
879 * ISR handler
880 *
881 * @return BOOLEAN indicates whether the IRQ came from us (TRUE) or not (FALSE)
882 * @param interrupt Interrupt that was triggered.
883 * @param serviceContext Context specific pointer.
884 */
885BOOLEAN VBoxGuestIsrHandler(PKINTERRUPT interrupt, PVOID serviceContext)
886{
887 NTSTATUS rc;
888 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)serviceContext;
889 BOOLEAN fIRQTaken = FALSE;
890
891 dprintf(("VBoxGuest::VBoxGuestIsrHandler haveEvents = %d\n",
892 pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents));
893
894 /*
895 * now we have to find out whether it was our IRQ. Read the event mask
896 * from our device to see if there are any pending events
897 */
898 if (pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents)
899 {
900 /* Acknowlegde events. */
901 VMMDevEvents *req = pDevExt->irqAckEvents;
902
903 rc = VbglGRPerform (&req->header);
904 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
905 {
906 dprintf(("VBoxGuest::VBoxGuestIsrHandler: acknowledge events succeeded %#x\n",
907 req->events));
908
909 ASMAtomicOrU32((uint32_t *)&pDevExt->u32Events, req->events);
910 IoRequestDpc(pDevExt->deviceObject, pDevExt->currentIrp, NULL);
911 }
912 else
913 {
914 /* This can't be actually. This is sign of a serious problem. */
915 dprintf(("VBoxGuest::VBoxGuestIsrHandler: "
916 "acknowledge events failed rc = %d, header rc = %d\n",
917 rc, req->header.rc));
918 }
919
920 /* Mark IRQ as taken, there were events for us. */
921 fIRQTaken = TRUE;
922 }
923
924 return fIRQTaken;
925}
926
927/**
928 * Worker thread to do periodic things such as synchronize the
929 * system time and notify other drivers of events.
930 *
931 * @param pDevExt device extension pointer
932 */
933VOID vboxWorkerThread(PVOID context)
934{
935 PVBOXGUESTDEVEXT pDevExt;
936
937 pDevExt = (PVBOXGUESTDEVEXT)context;
938 dprintf(("VBoxGuest::vboxWorkerThread entered\n"));
939
940 VMMDevReqHostTime *req = NULL;
941
942 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHostTime), VMMDevReq_GetHostTime);
943
944 if (VBOX_FAILURE(rc))
945 {
946 dprintf(("VBoxGuest::vboxWorkerThread: could not allocate request buffer, exiting rc = %d!\n", rc));
947 return;
948 }
949
950 /* perform the hypervisor address space reservation */
951 reserveHypervisorMemory(pDevExt);
952
953 do
954 {
955 /*
956 * Do the time sync
957 */
958 {
959 LARGE_INTEGER systemTime;
960 #define TICKSPERSEC 10000000
961 #define TICKSPERMSEC 10000
962 #define SECSPERDAY 86400
963 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (uint64_t)SECSPERDAY)
964 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
965
966
967 req->header.rc = VERR_GENERAL_FAILURE;
968
969 rc = VbglGRPerform (&req->header);
970
971 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
972 {
973 uint64_t hostTime = req->time;
974
975 // Windows was originally designed in 1601...
976 systemTime.QuadPart = hostTime * (uint64_t)TICKSPERMSEC + (uint64_t)TICKS_1601_TO_1970;
977 dprintf(("VBoxGuest::vboxWorkerThread: synching time with host time (msec/UTC): %llu\n", hostTime));
978 ZwSetSystemTime(&systemTime, NULL);
979 }
980 else
981 {
982 dprintf(("VBoxGuest::PowerStateRequest: error performing request to VMMDev."
983 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
984 }
985 }
986
987 /*
988 * Go asleep unless we're supposed to terminate
989 */
990 if (!pDevExt->stopThread)
991 {
992 ULONG secWait = 60;
993 dprintf(("VBoxGuest::vboxWorkerThread: waiting for %u seconds...\n", secWait));
994 LARGE_INTEGER dueTime;
995 dueTime.QuadPart = -10000 * 1000 * (int)secWait;
996 if (KeWaitForSingleObject(&pDevExt->workerThreadRequest, Executive,
997 KernelMode, FALSE, &dueTime) == STATUS_SUCCESS)
998 {
999 KeResetEvent(&pDevExt->workerThreadRequest);
1000 }
1001 }
1002 } while (!pDevExt->stopThread);
1003
1004 dprintf(("VBoxGuest::vboxWorkerThread: we've been asked to terminate!\n"));
1005
1006 /* free our request buffer */
1007 VbglGRFree (&req->header);
1008
1009 if (pDevExt->workerThread)
1010 {
1011 ObDereferenceObject(pDevExt->workerThread);
1012 pDevExt->workerThread = NULL;
1013 }
1014 dprintf(("VBoxGuest::vboxWorkerThread: now really gone!\n"));
1015}
1016
1017/**
1018 * Create driver worker threads
1019 *
1020 * @returns NTSTATUS NT status code
1021 * @param pDevExt VBoxGuest device extension
1022 */
1023NTSTATUS createThreads(PVBOXGUESTDEVEXT pDevExt)
1024{
1025 NTSTATUS rc;
1026 HANDLE threadHandle;
1027 OBJECT_ATTRIBUTES objAttributes;
1028
1029 dprintf(("VBoxGuest::createThreads\n"));
1030
1031 // first setup the request semaphore
1032 KeInitializeEvent(&pDevExt->workerThreadRequest, SynchronizationEvent, FALSE);
1033
1034// the API has slightly changed after NT4
1035#ifdef TARGET_NT4
1036#ifdef OBJ_KERNEL_HANDLE
1037#undef OBJ_KERNEL_HANDLE
1038#endif
1039#define OBJ_KERNEL_HANDLE 0
1040#endif
1041
1042 /*
1043 * The worker thread
1044 */
1045 InitializeObjectAttributes(&objAttributes,
1046 NULL,
1047 OBJ_KERNEL_HANDLE,
1048 NULL,
1049 NULL);
1050
1051 rc = PsCreateSystemThread(&threadHandle,
1052 THREAD_ALL_ACCESS,
1053 &objAttributes,
1054 (HANDLE)0L,
1055 NULL,
1056 vboxWorkerThread,
1057 pDevExt);
1058 dprintf(("VBoxGuest::createThreads: PsCreateSystemThread for worker thread returned: 0x%x\n", rc));
1059 rc = ObReferenceObjectByHandle(threadHandle,
1060 THREAD_ALL_ACCESS,
1061 NULL,
1062 KernelMode,
1063 (PVOID*)&pDevExt->workerThread,
1064 NULL);
1065 ZwClose(threadHandle);
1066
1067 /*
1068 * The idle thread
1069 */
1070#if 0 /// @todo Windows "sees" that time is lost and reports 100% usage
1071 rc = PsCreateSystemThread(&threadHandle,
1072 THREAD_ALL_ACCESS,
1073 &objAttributes,
1074 (HANDLE)0L,
1075 NULL,
1076 vboxIdleThread,
1077 pDevExt);
1078 dprintf(("VBoxGuest::createThreads: PsCreateSystemThread for idle thread returned: 0x%x\n", rc));
1079 rc = ObReferenceObjectByHandle(threadHandle,
1080 THREAD_ALL_ACCESS,
1081 NULL,
1082 KernelMode,
1083 (PVOID*)&pDevExt->idleThread,
1084 NULL);
1085 ZwClose(threadHandle);
1086#endif
1087
1088 return rc;
1089}
1090
1091/**
1092 * Helper routine to reserve address space for the hypervisor
1093 * and communicate its position.
1094 *
1095 * @param pDevExt Device extension structure.
1096 */
1097VOID reserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt)
1098{
1099 // @todo rc handling
1100 uint32_t hypervisorSize;
1101
1102 VMMDevReqHypervisorInfo *req = NULL;
1103
1104 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_GetHypervisorInfo);
1105
1106 if (VBOX_SUCCESS(rc))
1107 {
1108 req->hypervisorStart = 0;
1109 req->hypervisorSize = 0;
1110
1111 rc = VbglGRPerform (&req->header);
1112
1113 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
1114 {
1115 hypervisorSize = req->hypervisorSize;
1116
1117 if (!hypervisorSize)
1118 {
1119 dprintf(("VBoxGuest::reserveHypervisorMemory: host returned 0, not doing anything\n"));
1120 return;
1121 }
1122
1123 dprintf(("VBoxGuest::reserveHypervisorMemory: host wants %u bytes of hypervisor address space\n", hypervisorSize));
1124
1125 // Map fictive physical memory into the kernel address space to reserve virtual
1126 // address space. This API does not perform any checks but just allocate the
1127 // PTEs (which we don't really need/want but there isn't any other clean method).
1128 // The hypervisor only likes 4MB aligned virtual addresses, so we have to allocate
1129 // 4MB more than we are actually supposed to in order to guarantee that. Maybe we
1130 // can come up with a less lavish algorithm lateron.
1131 PHYSICAL_ADDRESS physAddr;
1132 physAddr.QuadPart = HYPERVISOR_PHYSICAL_START;
1133 pDevExt->hypervisorMappingSize = hypervisorSize + 0x400000;
1134 pDevExt->hypervisorMapping = MmMapIoSpace(physAddr,
1135 pDevExt->hypervisorMappingSize,
1136 MmNonCached);
1137 if (!pDevExt->hypervisorMapping)
1138 {
1139 dprintf(("VBoxGuest::reserveHypervisorMemory: MmMapIoSpace returned NULL!\n"));
1140 return;
1141 }
1142
1143 dprintf(("VBoxGuest::reserveHypervisorMemory: MmMapIoSpace returned %p\n", pDevExt->hypervisorMapping));
1144 dprintf(("VBoxGuest::reserveHypervisorMemory: communicating %p to host\n",
1145 ALIGNP(pDevExt->hypervisorMapping, 0x400000)));
1146
1147 /* align at 4MB */
1148 req->hypervisorStart = (RTGCPTR)ALIGNP(pDevExt->hypervisorMapping, 0x400000);
1149
1150 req->header.requestType = VMMDevReq_SetHypervisorInfo;
1151 req->header.rc = VERR_GENERAL_FAILURE;
1152
1153 /* issue request */
1154 rc = VbglGRPerform (&req->header);
1155
1156 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
1157 {
1158 dprintf(("VBoxGuest::reserveHypervisorMemory: error communicating physical address to VMMDev!"
1159 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
1160 }
1161 }
1162 else
1163 {
1164 dprintf(("VBoxGuest::reserveHypervisorMemory: request failed with rc %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
1165 }
1166 VbglGRFree (&req->header);
1167 }
1168
1169 return;
1170}
1171
1172/**
1173 * Helper function to unregister a virtual address space mapping
1174 *
1175 * @param pDevExt Device extension
1176 */
1177VOID unreserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt)
1178{
1179 VMMDevReqHypervisorInfo *req = NULL;
1180
1181 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_SetHypervisorInfo);
1182
1183 if (VBOX_SUCCESS(rc))
1184 {
1185 /* tell the hypervisor that the mapping is no longer available */
1186
1187 req->hypervisorStart = 0;
1188 req->hypervisorSize = 0;
1189
1190 rc = VbglGRPerform (&req->header);
1191
1192 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
1193 {
1194 dprintf(("VBoxGuest::unreserveHypervisorMemory: error communicating physical address to VMMDev!"
1195 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
1196 }
1197
1198 VbglGRFree (&req->header);
1199 }
1200
1201 if (!pDevExt->hypervisorMapping)
1202 {
1203 dprintf(("VBoxGuest::unreserveHypervisorMemory: there is no mapping, returning\n"));
1204 return;
1205 }
1206
1207 // unmap fictive IO space
1208 MmUnmapIoSpace(pDevExt->hypervisorMapping, pDevExt->hypervisorMappingSize);
1209 dprintf(("VBoxGuest::unreserveHypervisorMemmory: done\n"));
1210}
1211
1212/**
1213 * Idle thread that runs at the lowest priority possible
1214 * and whenever scheduled, makes a VMMDev call to give up
1215 * timeslices. This is so prevent Windows from thinking that
1216 * nothing is happening on the machine and doing stupid things
1217 * that would steal time from other VMs it doesn't know of.
1218 *
1219 * @param pDevExt device extension pointer
1220 */
1221VOID vboxIdleThread(PVOID context)
1222{
1223 PVBOXGUESTDEVEXT pDevExt;
1224
1225 pDevExt = (PVBOXGUESTDEVEXT)context;
1226 dprintf(("VBoxGuest::vboxIdleThread entered\n"));
1227
1228 /* set priority as low as possible */
1229 KeSetPriorityThread(KeGetCurrentThread(), LOW_PRIORITY);
1230
1231 /* allocate VMMDev request structure */
1232 VMMDevReqIdle *req;
1233 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_Idle);
1234 if (VBOX_FAILURE(rc))
1235 {
1236 dprintf(("VBoxGuest::vboxIdleThread: error %Vrc allocating request structure!\n"));
1237 return;
1238 }
1239
1240 do
1241 {
1242 //dprintf(("VBoxGuest: performing idle request..\n"));
1243 /* perform idle request */
1244 VbglGRPerform(&req->header);
1245
1246 } while (!pDevExt->stopThread);
1247
1248 VbglGRFree(&req->header);
1249
1250 dprintf(("VBoxGuest::vboxIdleThread leaving\n"));
1251}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette