VirtualBox

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

Last change on this file since 15844 was 15811, checked in by vboxsync, 16 years ago

Support 32 bit IOCtls in the Windows 64 bit guest driver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.9 KB
Line 
1/** @file
2 *
3 * VBoxGuest -- VirtualBox Win32 guest support driver
4 *
5 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 (GPL) as published by the Free Software
11 * Foundation, in version 2 as it comes in the "COPYING" file of the
12 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
14 *
15 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
16 * Clara, CA 95054 USA or visit http://www.sun.com if you need
17 * additional information or have any questions.
18 */
19
20// enable backdoor logging
21//#define LOG_ENABLED
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include "VBoxGuest_Internal.h"
27#ifdef TARGET_NT4
28#include "NTLegacy.h"
29#else
30#include "VBoxGuestPnP.h"
31#endif
32#include "Helper.h"
33#include <excpt.h>
34#include <VBox/err.h>
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38#include <iprt/mem.h>
39#include <stdio.h>
40#include <VBox/VBoxGuestLib.h>
41#include <VBoxGuestInternal.h>
42
43#ifdef TARGET_NT4
44/* XP DDK #defines ExFreePool to ExFreePoolWithTag. The latter does not exist on NT4, so...
45 * The same for ExAllocatePool.
46 */
47#undef ExAllocatePool
48#undef ExFreePool
49#endif
50
51/*******************************************************************************
52* Defined Constants And Macros *
53*******************************************************************************/
54
55
56/*******************************************************************************
57* Internal Functions *
58*******************************************************************************/
59extern "C"
60{
61static NTSTATUS VBoxGuestAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj);
62static void VBoxGuestUnload(PDRIVER_OBJECT pDrvObj);
63static NTSTATUS VBoxGuestCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
64static NTSTATUS VBoxGuestClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
65static NTSTATUS VBoxGuestDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
66static NTSTATUS VBoxGuestSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
67static NTSTATUS VBoxGuestShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp);
68static NTSTATUS VBoxGuestNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
69static VOID vboxWorkerThread(PVOID context);
70static VOID reserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt);
71static VOID vboxIdleThread(PVOID context);
72}
73
74
75/*******************************************************************************
76* Exported Functions *
77*******************************************************************************/
78__BEGIN_DECLS
79ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
80__END_DECLS
81
82#ifdef ALLOC_PRAGMA
83#pragma alloc_text (INIT, DriverEntry)
84#pragma alloc_text (PAGE, createThreads)
85#pragma alloc_text (PAGE, unreserveHypervisorMemory)
86#pragma alloc_text (PAGE, VBoxGuestAddDevice)
87#pragma alloc_text (PAGE, VBoxGuestUnload)
88#pragma alloc_text (PAGE, VBoxGuestCreate)
89#pragma alloc_text (PAGE, VBoxGuestClose)
90#pragma alloc_text (PAGE, VBoxGuestDeviceControl)
91#pragma alloc_text (PAGE, VBoxGuestShutdown)
92#pragma alloc_text (PAGE, VBoxGuestNotSupportedStub)
93/* Note: at least the isr handler should be in non-pageable memory! */
94/*#pragma alloc_text (PAGE, VBoxGuestDpcHandler)
95 #pragma alloc_text (PAGE, VBoxGuestIsrHandler) */
96#pragma alloc_text (PAGE, vboxWorkerThread)
97#pragma alloc_text (PAGE, reserveHypervisorMemory)
98#pragma alloc_text (PAGE, vboxIdleThread)
99#endif
100
101winVersion_t winVersion;
102
103/**
104 * Driver entry point.
105 *
106 * @returns appropriate status code.
107 * @param pDrvObj Pointer to driver object.
108 * @param pRegPath Registry base path.
109 */
110ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
111{
112 NTSTATUS rc = STATUS_SUCCESS;
113
114 dprintf(("VBoxGuest::DriverEntry. Driver built: %s %s\n", __DATE__, __TIME__));
115
116 ULONG majorVersion;
117 ULONG minorVersion;
118 ULONG buildNumber;
119 PsGetVersion(&majorVersion, &minorVersion, &buildNumber, NULL);
120 dprintf(("VBoxGuest::DriverEntry: running on Windows NT version %d.%d, build %d\n", majorVersion, minorVersion, buildNumber));
121 switch (majorVersion)
122 {
123 case 6:
124 winVersion = WINVISTA;
125 break;
126 case 5:
127 switch (minorVersion)
128 {
129 case 2:
130 winVersion = WIN2K3;
131 break;
132 case 1:
133 winVersion = WINXP;
134 break;
135 case 0:
136 winVersion = WIN2K;
137 break;
138 default:
139 dprintf(("VBoxGuest::DriverEntry: unknown version of Windows, refusing!\n"));
140 return STATUS_DRIVER_UNABLE_TO_LOAD;
141 }
142 break;
143 case 4:
144 winVersion = WINNT4;
145 break;
146 default:
147 dprintf(("VBoxGuest::DriverEntry: NT4 required!\n"));
148 return STATUS_DRIVER_UNABLE_TO_LOAD;
149 }
150
151 /*
152 * Setup the driver entry points in pDrvObj.
153 */
154 pDrvObj->DriverUnload = VBoxGuestUnload;
155 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxGuestCreate;
156 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxGuestClose;
157 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxGuestDeviceControl;
158 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxGuestDeviceControl;
159 pDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = VBoxGuestShutdown;
160 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxGuestNotSupportedStub;
161 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxGuestNotSupportedStub;
162#ifdef TARGET_NT4
163 rc = ntCreateDevice(pDrvObj, NULL, pRegPath);
164#else
165 pDrvObj->MajorFunction[IRP_MJ_PNP] = VBoxGuestPnP;
166 pDrvObj->MajorFunction[IRP_MJ_POWER] = VBoxGuestPower;
167 pDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = VBoxGuestSystemControl;
168 pDrvObj->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)VBoxGuestAddDevice;
169#endif
170
171 dprintf(("VBoxGuest::DriverEntry returning %#x\n", rc));
172 return rc;
173}
174
175#ifndef TARGET_NT4
176/**
177 * Handle request from the Plug & Play subsystem
178 *
179 * @returns NT status code
180 * @param pDrvObj Driver object
181 * @param pDevObj Device object
182 */
183static NTSTATUS VBoxGuestAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
184{
185 NTSTATUS rc;
186 dprintf(("VBoxGuest::VBoxGuestAddDevice\n"));
187
188 /*
189 * Create device.
190 */
191 PDEVICE_OBJECT deviceObject = NULL;
192 UNICODE_STRING devName;
193 RtlInitUnicodeString(&devName, VBOXGUEST_DEVICE_NAME_NT);
194 rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXT), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject);
195 if (!NT_SUCCESS(rc))
196 {
197 dprintf(("VBoxGuest::VBoxGuestAddDevice: IoCreateDevice failed with rc=%#x!\n", rc));
198 return rc;
199 }
200 UNICODE_STRING win32Name;
201 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
202 rc = IoCreateSymbolicLink(&win32Name, &devName);
203 if (!NT_SUCCESS(rc))
204 {
205 dprintf(("VBoxGuest::VBoxGuestAddDevice: IoCreateSymbolicLink failed with rc=%#x!\n", rc));
206 IoDeleteDevice(deviceObject);
207 return rc;
208 }
209
210 /*
211 * Setup the device extension.
212 */
213 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)deviceObject->DeviceExtension;
214 RtlZeroMemory(pDevExt, sizeof(VBOXGUESTDEVEXT));
215
216 pDevExt->deviceObject = deviceObject;
217 pDevExt->devState = STOPPED;
218
219 pDevExt->nextLowerDriver = IoAttachDeviceToDeviceStack(deviceObject, pDevObj);
220 if (pDevExt->nextLowerDriver == NULL)
221 {
222 dprintf(("VBoxGuest::VBoxGuestAddDevice: IoAttachDeviceToDeviceStack did not give a nextLowerDrive\n"));
223 IoDeleteSymbolicLink(&win32Name);
224 IoDeleteDevice(deviceObject);
225 return STATUS_DEVICE_NOT_CONNECTED;
226 }
227
228 // driver is ready now
229 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
230
231 dprintf(("VBoxGuest::VBoxGuestAddDevice: returning with rc = 0x%x\n", rc));
232 return rc;
233}
234#endif
235
236
237/**
238 * Unload the driver.
239 *
240 * @param pDrvObj Driver object.
241 */
242void VBoxGuestUnload(PDRIVER_OBJECT pDrvObj)
243{
244 dprintf(("VBoxGuest::VBoxGuestUnload\n"));
245#ifdef TARGET_NT4
246 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDrvObj->DeviceObject->DeviceExtension;
247 unreserveHypervisorMemory(pDevExt);
248 if (pDevExt->workerThread)
249 {
250 dprintf(("VBoxGuest::VBoxGuestUnload: waiting for the worker thread to terminate...\n"));
251 pDevExt->stopThread = TRUE;
252 KeSetEvent(&pDevExt->workerThreadRequest, 0, FALSE);
253 KeWaitForSingleObject(pDevExt->workerThread,
254 Executive, KernelMode, FALSE, NULL);
255 dprintf(("VBoxGuest::VBoxGuestUnload: returned from KeWaitForSingleObject for worker thread\n"));
256 }
257 if (pDevExt->idleThread)
258 {
259 dprintf(("VBoxGuest::VBoxGuestUnload: waiting for the idle thread to terminate...\n"));
260 pDevExt->stopThread = TRUE;
261 KeWaitForSingleObject(pDevExt->idleThread,
262 Executive, KernelMode, FALSE, NULL);
263 dprintf(("VBoxGuest::VBoxGuestUnload: returned from KeWaitForSingleObject for idle thread\n"));
264 }
265
266 hlpVBoxUnmapVMMDevMemory (pDevExt);
267
268 VBoxCleanupMemBalloon(pDevExt);
269
270 /*
271 * I don't think it's possible to unload a driver which processes have
272 * opened, at least we'll blindly assume that here.
273 */
274 UNICODE_STRING win32Name;
275 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
276 NTSTATUS rc = IoDeleteSymbolicLink(&win32Name);
277 IoDeleteDevice(pDrvObj->DeviceObject);
278#endif
279 dprintf(("VBoxGuest::VBoxGuestUnload: returning\n"));
280}
281
282
283/**
284 * Create (i.e. Open) file entry point.
285 *
286 * @param pDevObj Device object.
287 * @param pIrp Request packet.
288 */
289NTSTATUS VBoxGuestCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
290{
291 dprintf(("VBoxGuest::VBoxGuestCreate\n"));
292
293 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
294 PFILE_OBJECT pFileObj = pStack->FileObject;
295 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
296
297 /*
298 * We are not remotely similar to a directory...
299 * (But this is possible.)
300 */
301 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
302 {
303 dprintf(("VBoxGuest::VBoxGuestCreate: we're not a directory!\n"));
304 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
305 pIrp->IoStatus.Information = 0;
306 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
307 return STATUS_NOT_A_DIRECTORY;
308 }
309
310 NTSTATUS rcNt = pIrp->IoStatus.Status = STATUS_SUCCESS;
311 pIrp->IoStatus.Information = 0;
312 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
313
314 dprintf(("VBoxGuest::VBoxGuestCreate: returning 0x%x\n", rcNt));
315 return rcNt;
316}
317
318
319/**
320 * Close file entry point.
321 *
322 * @param pDevObj Device object.
323 * @param pIrp Request packet.
324 */
325NTSTATUS VBoxGuestClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
326{
327 dprintf(("VBoxGuest::VBoxGuestClose\n"));
328
329 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
330 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
331 PFILE_OBJECT pFileObj = pStack->FileObject;
332 dprintf(("VBoxGuest::VBoxGuestClose: pDevExt=%p pFileObj=%p pSession=%p\n",
333 pDevExt, pFileObj, pFileObj->FsContext));
334
335 pFileObj->FsContext = NULL;
336 pIrp->IoStatus.Information = 0;
337 pIrp->IoStatus.Status = STATUS_SUCCESS;
338 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
339
340 return STATUS_SUCCESS;
341}
342
343#ifdef VBOX_WITH_HGCM
344void VBoxHGCMCallbackWorker (VMMDevHGCMRequestHeader *pHeader, PVBOXGUESTDEVEXT pDevExt,
345 uint32_t u32Timeout, bool fInterruptible)
346{
347 /* Possible problem with request completion right between the fu32Flags check and KeWaitForSingleObject
348 * call; introduce a timeout to make sure we don't wait indefinitely.
349 */
350
351 LARGE_INTEGER timeout;
352 if (u32Timeout == RT_INDEFINITE_WAIT)
353 timeout.QuadPart = pDevExt->HGCMWaitTimeout.QuadPart;
354 else
355 {
356 timeout.QuadPart = u32Timeout;
357 timeout.QuadPart *= -10000; /* relative in 100ns units */
358 }
359 while ((pHeader->fu32Flags & VBOX_HGCM_REQ_DONE) == 0)
360 {
361 /* Specifying UserMode so killing the user process will abort the wait. */
362 NTSTATUS rc = KeWaitForSingleObject (&pDevExt->keventNotification, Executive,
363 UserMode,
364 fInterruptible ? TRUE : FALSE, /* Alertable */
365 &timeout
366 );
367 dprintf(("VBoxHGCMCallback: Wait returned %d fu32Flags=%x\n", rc, pHeader->fu32Flags));
368
369 if (rc == STATUS_TIMEOUT && u32Timeout == RT_INDEFINITE_WAIT)
370 continue;
371
372 if (rc != STATUS_WAIT_0)
373 {
374 dprintf(("VBoxHGCMCallback: The external event was signalled or the wait timed out or terminated rc = 0x%08X.\n", rc));
375 break;
376 }
377
378 dprintf(("VBoxHGCMCallback: fu32Flags = %08X\n", pHeader->fu32Flags));
379 }
380 return;
381}
382
383DECLVBGL(void) VBoxHGCMCallback (VMMDevHGCMRequestHeader *pHeader, void *pvData, uint32_t u32Data)
384{
385 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvData;
386
387 dprintf(("VBoxHGCMCallback\n"));
388 VBoxHGCMCallbackWorker (pHeader, pDevExt, u32Data, false);
389}
390
391DECLVBGL(void) VBoxHGCMCallbackInterruptible (VMMDevHGCMRequestHeader *pHeader, void *pvData,
392 uint32_t u32Data)
393{
394 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvData;
395
396 dprintf(("VBoxHGCMCallbackInterruptible\n"));
397 VBoxHGCMCallbackWorker (pHeader, pDevExt, u32Data, true);
398}
399
400NTSTATUS vboxHGCMVerifyIOBuffers (PIO_STACK_LOCATION pStack, unsigned cb)
401{
402 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < cb)
403 {
404 dprintf(("VBoxGuest::vboxHGCMVerifyIOBuffers: OutputBufferLength %d < %d\n",
405 pStack->Parameters.DeviceIoControl.OutputBufferLength, cb));
406 return STATUS_INVALID_PARAMETER;
407 }
408
409 if (pStack->Parameters.DeviceIoControl.InputBufferLength < cb)
410 {
411 dprintf(("VBoxGuest::vboxHGCMVerifyIOBuffers: InputBufferLength %d < %d\n",
412 pStack->Parameters.DeviceIoControl.InputBufferLength, cb));
413 return STATUS_INVALID_PARAMETER;
414 }
415
416 return STATUS_SUCCESS;
417}
418
419#endif /* VBOX_WITH_HGCM */
420
421static bool IsPowerOfTwo (uint32_t val)
422{
423 return (val & (val - 1)) == 0;
424}
425
426static bool CtlGuestFilterMask (uint32_t u32OrMask, uint32_t u32NotMask)
427{
428 bool result = false;
429 VMMDevCtlGuestFilterMask *req;
430 int rc = VbglGRAlloc ((VMMDevRequestHeader **) &req, sizeof (*req),
431 VMMDevReq_CtlGuestFilterMask);
432
433 if (RT_SUCCESS (rc))
434 {
435 req->u32OrMask = u32OrMask;
436 req->u32NotMask = u32NotMask;
437
438 rc = VbglGRPerform (&req->header);
439 if (RT_FAILURE (rc) || RT_FAILURE (req->header.rc))
440 {
441 dprintf (("VBoxGuest::VBoxGuestDeviceControl: error issuing request to VMMDev! "
442 "rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
443 }
444 else
445 {
446 result = true;
447 }
448 VbglGRFree (&req->header);
449 }
450
451 return result;
452}
453
454#ifdef VBOX_WITH_MANAGEMENT
455static int VBoxGuestSetBalloonSize(PVBOXGUESTDEVEXT pDevExt, uint32_t u32BalloonSize)
456{
457 VMMDevChangeMemBalloon *req = NULL;
458 int rc = VINF_SUCCESS;
459
460 if (u32BalloonSize > pDevExt->MemBalloon.cMaxBalloons)
461 {
462 AssertMsgFailed(("VBoxGuestSetBalloonSize illegal balloon size %d (max=%d)\n", u32BalloonSize, pDevExt->MemBalloon.cMaxBalloons));
463 return VERR_INVALID_PARAMETER;
464 }
465
466 if (u32BalloonSize == pDevExt->MemBalloon.cBalloons)
467 return VINF_SUCCESS; /* nothing to do */
468
469 /* Allocate request packet */
470 rc = VbglGRAlloc((VMMDevRequestHeader **)&req, RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]), VMMDevReq_ChangeMemBalloon);
471 if (RT_FAILURE(rc))
472 return rc;
473
474 vmmdevInitRequest(&req->header, VMMDevReq_ChangeMemBalloon);
475
476 if (u32BalloonSize > pDevExt->MemBalloon.cBalloons)
477 {
478 /* inflate */
479 for (uint32_t i=pDevExt->MemBalloon.cBalloons;i<u32BalloonSize;i++)
480 {
481#ifndef TARGET_NT4
482 /*
483 * Use MmAllocatePagesForMdl to specify the range of physical addresses we wish to use.
484 */
485 PHYSICAL_ADDRESS Zero;
486 PHYSICAL_ADDRESS HighAddr;
487 Zero.QuadPart = 0;
488 HighAddr.QuadPart = _4G - 1;
489 PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE);
490 if (pMdl)
491 {
492 if (MmGetMdlByteCount(pMdl) < VMMDEV_MEMORY_BALLOON_CHUNK_SIZE)
493 {
494 MmFreePagesFromMdl(pMdl);
495 ExFreePool(pMdl);
496 rc = VERR_NO_MEMORY;
497 goto end;
498 }
499 }
500#else
501 PVOID pvBalloon;
502 pvBalloon = ExAllocatePool(PagedPool, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE);
503 if (!pvBalloon)
504 {
505 rc = VERR_NO_MEMORY;
506 goto end;
507 }
508
509 PMDL pMdl = IoAllocateMdl (pvBalloon, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE, FALSE, FALSE, NULL);
510 if (pMdl == NULL)
511 {
512 rc = VERR_NO_MEMORY;
513 ExFreePool(pvBalloon);
514 AssertMsgFailed(("IoAllocateMdl %p %x failed!!\n", pvBalloon, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE));
515 goto end;
516 }
517 else
518 {
519 __try {
520 /* Calls to MmProbeAndLockPages must be enclosed in a try/except block. */
521 MmProbeAndLockPages (pMdl, KernelMode, IoModifyAccess);
522 }
523 __except(EXCEPTION_EXECUTE_HANDLER)
524 {
525 dprintf(("MmProbeAndLockPages failed!\n"));
526 rc = VERR_NO_MEMORY;
527 IoFreeMdl (pMdl);
528 ExFreePool(pvBalloon);
529 goto end;
530 }
531 }
532#endif
533
534 PPFN_NUMBER pPageDesc = MmGetMdlPfnArray(pMdl);
535
536 /* Copy manually as RTGCPHYS is always 64 bits */
537 for (uint32_t j=0;j<VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;j++)
538 req->aPhysPage[j] = pPageDesc[j];
539
540 req->header.size = RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]);
541 req->cPages = VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;
542 req->fInflate = true;
543
544 rc = VbglGRPerform(&req->header);
545 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
546 {
547 dprintf(("VBoxGuest::VBoxGuestSetBalloonSize: error issuing request to VMMDev!"
548 "rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
549
550#ifndef TARGET_NT4
551 MmFreePagesFromMdl(pMdl);
552 ExFreePool(pMdl);
553#else
554 IoFreeMdl (pMdl);
555 ExFreePool(pvBalloon);
556#endif
557 goto end;
558 }
559 else
560 {
561#ifndef TARGET_NT4
562 dprintf(("VBoxGuest::VBoxGuestSetBalloonSize %d MB added chunk at %x\n", i, pMdl));
563#else
564 dprintf(("VBoxGuest::VBoxGuestSetBalloonSize %d MB added chunk at %x\n", i, pvBalloon));
565#endif
566 pDevExt->MemBalloon.paMdlMemBalloon[i] = pMdl;
567 pDevExt->MemBalloon.cBalloons++;
568 }
569 }
570 }
571 else
572 {
573 /* deflate */
574 for (uint32_t _i=pDevExt->MemBalloon.cBalloons;_i>u32BalloonSize;_i--)
575 {
576 uint32_t index = _i - 1;
577 PMDL pMdl = pDevExt->MemBalloon.paMdlMemBalloon[index];
578
579 Assert(pMdl);
580 if (pMdl)
581 {
582#ifdef TARGET_NT4
583 PVOID pvBalloon = MmGetMdlVirtualAddress(pMdl);
584#endif
585
586 PPFN_NUMBER pPageDesc = MmGetMdlPfnArray(pMdl);
587
588 /* Copy manually as RTGCPHYS is always 64 bits */
589 for (uint32_t j=0;j<VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;j++)
590 req->aPhysPage[j] = pPageDesc[j];
591
592 req->header.size = RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]);
593 req->cPages = VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;
594 req->fInflate = false;
595
596 rc = VbglGRPerform(&req->header);
597 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
598 {
599 AssertMsgFailed(("VBoxGuest::VBoxGuestSetBalloonSize: error issuing request to VMMDev! rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
600 break;
601 }
602
603 /* Free the ballooned memory */
604#ifndef TARGET_NT4
605 dprintf(("VBoxGuest::VBoxGuestSetBalloonSize %d MB free chunk at %x\n", index, pMdl));
606 MmFreePagesFromMdl(pMdl);
607 ExFreePool(pMdl);
608#else
609 dprintf(("VBoxGuest::VBoxGuestSetBalloonSize %d MB free chunk at %x\n", index, pvBalloon));
610 MmUnlockPages (pMdl);
611 IoFreeMdl (pMdl);
612 ExFreePool(pvBalloon);
613#endif
614
615 pDevExt->MemBalloon.paMdlMemBalloon[index] = NULL;
616 pDevExt->MemBalloon.cBalloons--;
617 }
618 }
619 }
620 Assert(pDevExt->MemBalloon.cBalloons <= pDevExt->MemBalloon.cMaxBalloons);
621
622end:
623 VbglGRFree(&req->header);
624 return rc;
625}
626
627static int VBoxGuestQueryMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, ULONG *pMemBalloonSize)
628{
629 /* just perform the request */
630 VMMDevGetMemBalloonChangeRequest *req = NULL;
631
632 dprintf(("VBoxGuestQueryMemoryBalloon\n"));
633
634 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, sizeof(VMMDevGetMemBalloonChangeRequest), VMMDevReq_GetMemBalloonChangeRequest);
635 vmmdevInitRequest(&req->header, VMMDevReq_GetMemBalloonChangeRequest);
636 req->eventAck = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
637
638 if (RT_SUCCESS(rc))
639 {
640 rc = VbglGRPerform(&req->header);
641
642 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
643 {
644 dprintf(("VBoxGuest::VBoxGuestDeviceControl VBOXGUEST_IOCTL_CTL_CHECK_BALLOON: error issuing request to VMMDev!"
645 "rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
646 }
647 else
648 {
649 if (!pDevExt->MemBalloon.paMdlMemBalloon)
650 {
651 pDevExt->MemBalloon.cMaxBalloons = req->u32PhysMemSize;
652 pDevExt->MemBalloon.paMdlMemBalloon = (PMDL *)ExAllocatePool(PagedPool, req->u32PhysMemSize * sizeof(PMDL));
653 Assert(pDevExt->MemBalloon.paMdlMemBalloon);
654 if (!pDevExt->MemBalloon.paMdlMemBalloon)
655 return VERR_NO_MEMORY;
656 }
657 Assert(pDevExt->MemBalloon.cMaxBalloons == req->u32PhysMemSize);
658
659 rc = VBoxGuestSetBalloonSize(pDevExt, req->u32BalloonSize);
660 /* ignore out of memory failures */
661 if (rc == VERR_NO_MEMORY)
662 rc = VINF_SUCCESS;
663
664 if (pMemBalloonSize)
665 *pMemBalloonSize = pDevExt->MemBalloon.cBalloons;
666 }
667
668 VbglGRFree(&req->header);
669 }
670 return rc;
671}
672#endif
673
674void VBoxInitMemBalloon(PVBOXGUESTDEVEXT pDevExt)
675{
676#ifdef VBOX_WITH_MANAGEMENT
677 ULONG dummy;
678
679 pDevExt->MemBalloon.cBalloons = 0;
680 pDevExt->MemBalloon.cMaxBalloons = 0;
681 pDevExt->MemBalloon.paMdlMemBalloon = NULL;
682
683 VBoxGuestQueryMemoryBalloon(pDevExt, &dummy);
684#endif
685}
686
687void VBoxCleanupMemBalloon(PVBOXGUESTDEVEXT pDevExt)
688{
689#ifdef VBOX_WITH_MANAGEMENT
690 if (pDevExt->MemBalloon.paMdlMemBalloon)
691 {
692 /* Clean up the memory balloon leftovers */
693 VBoxGuestSetBalloonSize(pDevExt, 0);
694 ExFreePool(pDevExt->MemBalloon.paMdlMemBalloon);
695 pDevExt->MemBalloon.paMdlMemBalloon = NULL;
696 }
697 Assert(pDevExt->MemBalloon.cBalloons == 0);
698#endif
699}
700
701/**
702 * Device I/O Control entry point.
703 *
704 * @param pDevObj Device object.
705 * @param pIrp Request packet.
706 */
707NTSTATUS VBoxGuestDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
708{
709 dprintf(("VBoxGuest::VBoxGuestDeviceControl\n"));
710
711 NTSTATUS Status = STATUS_SUCCESS;
712
713 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
714
715 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
716
717 char *pBuf = (char *)pIrp->AssociatedIrp.SystemBuffer; /* all requests are buffered. */
718
719 unsigned cbOut = 0;
720
721 switch (pStack->Parameters.DeviceIoControl.IoControlCode)
722 {
723 case VBOXGUEST_IOCTL_GETVMMDEVPORT:
724 {
725 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_GETVMMDEVPORT\n"));
726
727 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof (VBoxGuestPortInfo))
728 {
729 Status = STATUS_BUFFER_TOO_SMALL;
730 break;
731 }
732
733 VBoxGuestPortInfo *portInfo = (VBoxGuestPortInfo*)pBuf;
734
735 portInfo->portAddress = pDevExt->startPortAddress;
736 portInfo->pVMMDevMemory = pDevExt->pVMMDevMemory;
737
738 cbOut = sizeof(VBoxGuestPortInfo);
739
740 break;
741 }
742
743 case VBOXGUEST_IOCTL_WAITEVENT:
744 {
745 /* Need to be extended to support multiple waiters for an event,
746 * array of counters for each event, event mask is computed, each
747 * time a wait event is arrived.
748 */
749 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_WAITEVENT\n"));
750
751 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VBoxGuestWaitEventInfo))
752 {
753 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d < sizeof(VBoxGuestWaitEventInfo)\n",
754 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestWaitEventInfo)));
755 Status = STATUS_BUFFER_TOO_SMALL;
756 break;
757 }
758
759 if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VBoxGuestWaitEventInfo)) {
760 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < sizeof(VBoxGuestWaitEventInfo)\n",
761 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestWaitEventInfo)));
762 Status = STATUS_BUFFER_TOO_SMALL;
763 break;
764 }
765
766 VBoxGuestWaitEventInfo *eventInfo = (VBoxGuestWaitEventInfo *)pBuf;
767
768 if (!eventInfo->u32EventMaskIn || !IsPowerOfTwo (eventInfo->u32EventMaskIn)) {
769 dprintf (("VBoxGuest::VBoxGuestDeviceControl: Invalid input mask %#x\n",
770 eventInfo->u32EventMaskIn));
771 Status = STATUS_INVALID_PARAMETER;
772 break;
773 }
774
775 eventInfo->u32EventFlagsOut = 0;
776 int iBitOffset = ASMBitFirstSetU32 (eventInfo->u32EventMaskIn) - 1;
777 bool fTimeout = (eventInfo->u32TimeoutIn != ~0L);
778
779 dprintf (("mask = %d, iBitOffset = %d\n", iBitOffset, eventInfo->u32EventMaskIn));
780
781 /* Possible problem with request completion right between the pending event check and KeWaitForSingleObject
782 * call; introduce a timeout (if none was specified) to make sure we don't wait indefinitely.
783 */
784 LARGE_INTEGER timeout;
785 timeout.QuadPart = (fTimeout) ? eventInfo->u32TimeoutIn : 250;
786 timeout.QuadPart *= -10000;
787
788 NTSTATUS rc = STATUS_SUCCESS;
789
790 for (;;)
791 {
792 bool fEventPending = ASMAtomicBitTestAndClear(&pDevExt->u32Events, iBitOffset);
793 if (fEventPending)
794 {
795 eventInfo->u32EventFlagsOut = 1 << iBitOffset;
796 break;
797 }
798
799 rc = KeWaitForSingleObject (&pDevExt->keventNotification, Executive /** @todo UserRequest? */,
800 KernelMode, TRUE, &timeout);
801 dprintf(("VBOXGUEST_IOCTL_WAITEVENT: Wait returned %d -> event %x\n", rc, eventInfo->u32EventFlagsOut));
802
803 if (!fTimeout && rc == STATUS_TIMEOUT)
804 continue;
805
806 if (rc != STATUS_SUCCESS)
807 {
808 /* There was a timeout or wait was interrupted, etc. */
809 break;
810 }
811 }
812
813 dprintf (("u32EventFlagsOut = %#x\n", eventInfo->u32EventFlagsOut));
814 cbOut = sizeof(VBoxGuestWaitEventInfo);
815 break;
816 }
817
818 case VBOXGUEST_IOCTL_VMMREQUEST(0): /* (The size isn't relevant on NT.)*/
819 {
820 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_VMMREQUEST\n"));
821
822#define CHECK_SIZE(s) \
823 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < s) \
824 { \
825 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d < %d\n", \
826 pStack->Parameters.DeviceIoControl.OutputBufferLength, s)); \
827 Status = STATUS_BUFFER_TOO_SMALL; \
828 break; \
829 } \
830 if (pStack->Parameters.DeviceIoControl.InputBufferLength < s) { \
831 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < %d\n", \
832 pStack->Parameters.DeviceIoControl.InputBufferLength, s)); \
833 Status = STATUS_BUFFER_TOO_SMALL; \
834 break; \
835 }
836
837 /* get the request header */
838 CHECK_SIZE(sizeof(VMMDevRequestHeader));
839 VMMDevRequestHeader *requestHeader = (VMMDevRequestHeader *)pBuf;
840 if (!vmmdevGetRequestSize(requestHeader->requestType))
841 {
842 Status = STATUS_INVALID_PARAMETER;
843 break;
844 }
845 /* make sure the buffers suit the request */
846 CHECK_SIZE(vmmdevGetRequestSize(requestHeader->requestType));
847
848 /* just perform the request */
849 VMMDevRequestHeader *req = NULL;
850
851 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, requestHeader->size, requestHeader->requestType);
852
853 if (RT_SUCCESS(rc))
854 {
855 /* copy the request information */
856 memcpy((void*)req, (void*)pBuf, requestHeader->size);
857 rc = VbglGRPerform(req);
858
859 if (RT_FAILURE(rc) || RT_FAILURE(req->rc))
860 {
861 dprintf(("VBoxGuest::VBoxGuestDeviceControl VBOXGUEST_IOCTL_VMMREQUEST: Error issuing request to VMMDev! "
862 "rc = %d, VMMDev rc = %Rrc\n", rc, req->rc));
863 Status = STATUS_UNSUCCESSFUL;
864 }
865 else
866 {
867 /* copy result */
868 memcpy((void*)pBuf, (void*)req, requestHeader->size);
869 cbOut = requestHeader->size;
870 }
871
872 VbglGRFree(req);
873 }
874 else
875 {
876 Status = STATUS_UNSUCCESSFUL;
877 }
878#undef CHECK_SIZE
879 break;
880 }
881
882 case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
883 {
884 VBoxGuestFilterMaskInfo *maskInfo;
885
886 if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VBoxGuestFilterMaskInfo)) {
887 dprintf (("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < %d\n",
888 pStack->Parameters.DeviceIoControl.InputBufferLength,
889 sizeof (VBoxGuestFilterMaskInfo)));
890 Status = STATUS_BUFFER_TOO_SMALL;
891 break;
892
893 }
894
895 maskInfo = (VBoxGuestFilterMaskInfo *) pBuf;
896 if (!CtlGuestFilterMask (maskInfo->u32OrMask, maskInfo->u32NotMask))
897 {
898 Status = STATUS_UNSUCCESSFUL;
899 }
900 break;
901 }
902
903#ifdef VBOX_WITH_HGCM
904 /* HGCM offers blocking IOCTLSs just like waitevent and actually
905 * uses the same waiting code.
906 */
907#ifdef RT_ARCH_AMD64
908 case VBOXGUEST_IOCTL_HGCM_CONNECT_32:
909#endif /* RT_ARCH_AMD64 */
910 case VBOXGUEST_IOCTL_HGCM_CONNECT:
911 {
912 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_HGCM_CONNECT\n"));
913
914 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(VBoxGuestHGCMConnectInfo))
915 {
916 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(VBoxGuestHGCMConnectInfo) %d\n",
917 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestHGCMConnectInfo)));
918 Status = STATUS_INVALID_PARAMETER;
919 break;
920 }
921
922 if (pStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(VBoxGuestHGCMConnectInfo)) {
923 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d != sizeof(VBoxGuestHGCMConnectInfo) %d\n",
924 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestHGCMConnectInfo)));
925 Status = STATUS_INVALID_PARAMETER;
926 break;
927 }
928
929 VBoxGuestHGCMConnectInfo *ptr = (VBoxGuestHGCMConnectInfo *)pBuf;
930
931 /* If request will be processed asynchronously, execution will
932 * go to VBoxHGCMCallback. There it will wait for the request event, signalled from IRQ.
933 * On IRQ arrival, the VBoxHGCMCallback(s) will check the request memory and, if completion
934 * flag is set, returns.
935 */
936
937 dprintf(("a) ptr->u32ClientID = %d\n", ptr->u32ClientID));
938
939 int rc = VbglHGCMConnect (ptr, VBoxHGCMCallback, pDevExt, RT_INDEFINITE_WAIT);
940
941 dprintf(("b) ptr->u32ClientID = %d\n", ptr->u32ClientID));
942
943 if (RT_FAILURE(rc))
944 {
945 dprintf(("VBOXGUEST_IOCTL_HGCM_CONNECT: vbox rc = %Rrc\n", rc));
946 Status = STATUS_UNSUCCESSFUL;
947 }
948 else
949 {
950 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
951 }
952
953 } break;
954
955#ifdef RT_ARCH_AMD64
956 case VBOXGUEST_IOCTL_HGCM_DISCONNECT_32:
957#endif /* RT_ARCH_AMD64 */
958 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
959 {
960 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_HGCM_DISCONNECT\n"));
961
962 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(VBoxGuestHGCMDisconnectInfo))
963 {
964 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(VBoxGuestHGCMDisconnectInfo) %d\n",
965 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestHGCMDisconnectInfo)));
966 Status = STATUS_INVALID_PARAMETER;
967 break;
968 }
969
970 if (pStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(VBoxGuestHGCMDisconnectInfo)) {
971 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d != sizeof(VBoxGuestHGCMDisconnectInfo) %d\n",
972 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestHGCMDisconnectInfo)));
973 Status = STATUS_INVALID_PARAMETER;
974 break;
975 }
976
977 VBoxGuestHGCMDisconnectInfo *ptr = (VBoxGuestHGCMDisconnectInfo *)pBuf;
978
979 /* If request will be processed asynchronously, execution will
980 * go to VBoxHGCMCallback. There it will wait for the request event, signalled from IRQ.
981 * On IRQ arrival, the VBoxHGCMCallback(s) will check the request memory and, if completion
982 * flag is set, returns.
983 */
984
985 int rc = VbglHGCMDisconnect (ptr, VBoxHGCMCallback, pDevExt, RT_INDEFINITE_WAIT);
986
987 if (RT_FAILURE(rc))
988 {
989 dprintf(("VBOXGUEST_IOCTL_HGCM_DISCONNECT: vbox rc = %Rrc\n", rc));
990 Status = STATUS_UNSUCCESSFUL;
991 }
992 else
993 {
994 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
995 }
996
997 } break;
998
999#ifdef RT_ARCH_AMD64
1000 case VBOXGUEST_IOCTL_HGCM_CALL_32(0): /* (The size isn't relevant on NT.) */
1001 {
1002 /* A 32 bit application call. */
1003 int rc;
1004
1005 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_HGCM_CALL_32\n"));
1006
1007 Status = vboxHGCMVerifyIOBuffers (pStack,
1008 sizeof (VBoxGuestHGCMCallInfo));
1009
1010 if (Status != STATUS_SUCCESS)
1011 {
1012 dprintf(("VBoxGuest::VBoxGuestDeviceControl: invalid parameter. Status: %p\n", Status));
1013 break;
1014 }
1015
1016 /* @todo: Old guest OpenGL driver used the same IOCtl code for both 32 and 64 bit binaries.
1017 * This is a protection, and can be removed if there were no 64 bit driver.
1018 */
1019 if (!IoIs32bitProcess(pIrp))
1020 {
1021 Status = STATUS_UNSUCCESSFUL;
1022 break;
1023 }
1024
1025 VBoxGuestHGCMCallInfo *ptr = (VBoxGuestHGCMCallInfo *)pBuf;
1026
1027 rc = VbglHGCMCall32(ptr, VBoxHGCMCallback, pDevExt, RT_INDEFINITE_WAIT);
1028
1029 if (RT_FAILURE(rc))
1030 {
1031 dprintf(("VBOXGUEST_IOCTL_HGCM_CALL_32: vbox rc = %Rrc\n", rc));
1032 Status = STATUS_UNSUCCESSFUL;
1033 }
1034 else
1035 {
1036 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1037 }
1038
1039 } break;
1040#endif /* RT_ARCH_AMD64 */
1041
1042 case VBOXGUEST_IOCTL_HGCM_CALL(0): /* (The size isn't relevant on NT.) */
1043 {
1044 int rc;
1045
1046 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_HGCM_CALL\n"));
1047
1048 Status = vboxHGCMVerifyIOBuffers (pStack,
1049 sizeof (VBoxGuestHGCMCallInfo));
1050
1051 if (Status != STATUS_SUCCESS)
1052 {
1053 dprintf(("VBoxGuest::VBoxGuestDeviceControl: invalid parameter. Status: %p\n", Status));
1054 break;
1055 }
1056
1057 VBoxGuestHGCMCallInfo *ptr = (VBoxGuestHGCMCallInfo *)pBuf;
1058
1059 rc = VbglHGCMCall (ptr, VBoxHGCMCallback, pDevExt, RT_INDEFINITE_WAIT);
1060
1061 if (RT_FAILURE(rc))
1062 {
1063 dprintf(("VBOXGUEST_IOCTL_HGCM_CALL: vbox rc = %Rrc\n", rc));
1064 Status = STATUS_UNSUCCESSFUL;
1065 }
1066 else
1067 {
1068 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1069 }
1070
1071 } break;
1072
1073 case VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0): /* (The size isn't relevant on NT.) */
1074 {
1075 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_HGCM_CALL_TIMED\n"));
1076
1077 Status = vboxHGCMVerifyIOBuffers (pStack,
1078 sizeof (VBoxGuestHGCMCallInfoTimed));
1079
1080 if (Status != STATUS_SUCCESS)
1081 {
1082 dprintf(("nvalid parameter. Status: %p\n", Status));
1083 break;
1084 }
1085
1086 VBoxGuestHGCMCallInfoTimed *pInfo = (VBoxGuestHGCMCallInfoTimed *)pBuf;
1087 VBoxGuestHGCMCallInfo *ptr = &pInfo->info;
1088
1089 int rc;
1090 if (pInfo->fInterruptible)
1091 {
1092 dprintf(("VBoxGuest::VBoxGuestDeviceControl: calling VBoxHGCMCall interruptible, timeout %lu ms\n",
1093 pInfo->u32Timeout));
1094 rc = VbglHGCMCall (ptr, VBoxHGCMCallbackInterruptible, pDevExt, pInfo->u32Timeout);
1095 }
1096 else
1097 {
1098 dprintf(("VBoxGuest::VBoxGuestDeviceControl: calling VBoxHGCMCall, timeout %lu ms\n",
1099 pInfo->u32Timeout));
1100 rc = VbglHGCMCall (ptr, VBoxHGCMCallback, pDevExt, pInfo->u32Timeout);
1101 }
1102
1103 if (RT_FAILURE(rc))
1104 {
1105 dprintf(("VBOXGUEST_IOCTL_HGCM_CALL_TIMED: vbox rc = %Rrc\n", rc));
1106 Status = STATUS_UNSUCCESSFUL;
1107 }
1108 else
1109 {
1110 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1111 }
1112
1113 } break;
1114#endif /* VBOX_WITH_HGCM */
1115
1116#ifdef VBOX_WITH_VRDP_SESSION_HANDLING
1117 case VBOXGUEST_IOCTL_ENABLE_VRDP_SESSION:
1118 {
1119 LogRel(("VRDP_SESSION: Enable. Currently: %sabled\n", pDevExt->fVRDPEnabled? "en": "dis"));
1120 if (!pDevExt->fVRDPEnabled)
1121 {
1122 KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
1123
1124 pDevExt->fVRDPEnabled = TRUE;
1125 LogRel(("VRDP_SESSION: Current active console id: 0x%08X\n", pSharedUserData->ActiveConsoleId));
1126 pDevExt->ulOldActiveConsoleId = pSharedUserData->ActiveConsoleId;
1127 pSharedUserData->ActiveConsoleId = 2;
1128 }
1129 break;
1130 }
1131
1132 case VBOXGUEST_IOCTL_DISABLE_VRDP_SESSION:
1133 {
1134 LogRel(("VRDP_SESSION: Disable. Currently: %sabled\n", pDevExt->fVRDPEnabled? "en": "dis"));
1135 if (pDevExt->fVRDPEnabled)
1136 {
1137 KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
1138
1139 pDevExt->fVRDPEnabled = FALSE;
1140 LogRel(("VRDP_SESSION: Current active console id: 0x%08X\n", pSharedUserData->ActiveConsoleId));
1141 pSharedUserData->ActiveConsoleId = pDevExt->ulOldActiveConsoleId;
1142 pDevExt->ulOldActiveConsoleId = 0;
1143 }
1144 break;
1145 }
1146#endif
1147
1148#ifdef VBOX_WITH_MANAGEMENT
1149 case VBOXGUEST_IOCTL_CTL_CHECK_BALLOON_MASK:
1150 {
1151 ULONG *pMemBalloonSize = (ULONG *) pBuf;
1152
1153 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
1154 {
1155 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(ULONG) %d\n",
1156 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(ULONG)));
1157 Status = STATUS_INVALID_PARAMETER;
1158 break;
1159 }
1160
1161 int rc = VBoxGuestQueryMemoryBalloon(pDevExt, pMemBalloonSize);
1162 if (RT_FAILURE(rc))
1163 {
1164 dprintf(("VBOXGUEST_IOCTL_CTL_CHECK_BALLOON: vbox rc = %Rrc\n", rc));
1165 Status = STATUS_UNSUCCESSFUL;
1166 }
1167 else
1168 {
1169 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1170 }
1171 break;
1172 }
1173#endif
1174
1175 case VBOXGUEST_IOCTL_LOG(0): /* The size isn't relevant on NT. */
1176 {
1177 /* Enable this only for debugging:
1178 dprintf(("VBoxGuest::VBoxGuestDeviceControl: VBOXGUEST_IOCTL_LOG %.*s\n", (int)pStack->Parameters.DeviceIoControl.InputBufferLength, pBuf));
1179 */
1180 LogRel(("%.*s", (int)pStack->Parameters.DeviceIoControl.InputBufferLength, pBuf));
1181 cbOut = 0;
1182 break;
1183 }
1184
1185 default:
1186 Status = STATUS_INVALID_PARAMETER;
1187 break;
1188 }
1189
1190 pIrp->IoStatus.Status = Status;
1191 pIrp->IoStatus.Information = cbOut;
1192
1193 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1194
1195 dprintf(("VBoxGuest::VBoxGuestDeviceControl: returned cbOut=%d rc=%#x\n", cbOut, Status));
1196
1197 return Status;
1198}
1199
1200
1201/**
1202 * IRP_MJ_SYSTEM_CONTROL handler
1203 *
1204 * @returns NT status code
1205 * @param pDevObj Device object.
1206 * @param pIrp IRP.
1207 */
1208NTSTATUS VBoxGuestSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1209{
1210 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
1211
1212 dprintf(("VBoxGuest::VBoxGuestSystemControl\n"));
1213
1214 /* Always pass it on to the next driver. */
1215 IoSkipCurrentIrpStackLocation(pIrp);
1216
1217 return IoCallDriver(pDevExt->nextLowerDriver, pIrp);
1218}
1219
1220/**
1221 * IRP_MJ_SHUTDOWN handler
1222 *
1223 * @returns NT status code
1224 * @param pDevObj Device object.
1225 * @param pIrp IRP.
1226 */
1227NTSTATUS VBoxGuestShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1228{
1229 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
1230
1231 dprintf(("VBoxGuest::VBoxGuestShutdown\n"));
1232
1233 if (pDevExt && pDevExt->powerStateRequest)
1234 {
1235 VMMDevPowerStateRequest *req = pDevExt->powerStateRequest;
1236
1237 req->header.requestType = VMMDevReq_SetPowerStatus;
1238 req->powerState = VMMDevPowerState_PowerOff;
1239
1240 int rc = VbglGRPerform (&req->header);
1241
1242 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
1243 {
1244 dprintf(("VBoxGuest::PowerStateRequest: error performing request to VMMDev."
1245 "rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
1246 }
1247 }
1248
1249 return STATUS_SUCCESS;
1250}
1251
1252/**
1253 * Stub function for functions we don't implemented.
1254 *
1255 * @returns STATUS_NOT_SUPPORTED
1256 * @param pDevObj Device object.
1257 * @param pIrp IRP.
1258 */
1259NTSTATUS VBoxGuestNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1260{
1261 dprintf(("VBoxGuest::VBoxGuestNotSupportedStub\n"));
1262 pDevObj = pDevObj;
1263
1264 pIrp->IoStatus.Information = 0;
1265 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1266 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1267
1268 return STATUS_NOT_SUPPORTED;
1269}
1270
1271/**
1272 * DPC handler
1273 *
1274 * @param dpc DPC descriptor.
1275 * @param pDevObj Device object.
1276 * @param irp Interrupt request packet.
1277 * @param context Context specific pointer.
1278 */
1279VOID VBoxGuestDpcHandler(PKDPC dpc, PDEVICE_OBJECT pDevObj,
1280 PIRP irp, PVOID context)
1281{
1282 /* Unblock handlers waiting for arrived events.
1283 *
1284 * Events are very low things, there is one event flag (1 or more bit)
1285 * for each event. Each event is processed by exactly one handler.
1286 *
1287 * Assume that we trust additions and that other drivers will
1288 * handle its respective events without trying to fetch all events.
1289 *
1290 * Anyway design assures that wrong event processing will affect only guest.
1291 *
1292 * Event handler calls VMMDev IOCTL for waiting an event.
1293 * It supplies event mask. IOCTL blocks on EventNotification.
1294 * Here we just signal an the EventNotification to all waiting
1295 * threads, the IOCTL handler analyzes events and either
1296 * return to caller or blocks again.
1297 *
1298 * If we do not have too many events this is a simple and good
1299 * approach. Other way is to have as many Event objects as the callers
1300 * and wake up only callers waiting for the specific event.
1301 *
1302 * Now with the 'wake up all' appoach we probably do not need the DPC
1303 * handler and can signal event directly from ISR.
1304 *
1305 */
1306
1307 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
1308
1309 dprintf(("VBoxGuest::VBoxGuestDpcHandler\n"));
1310
1311 KePulseEvent(&pDevExt->keventNotification, 0, FALSE);
1312
1313}
1314
1315/**
1316 * ISR handler
1317 *
1318 * @return BOOLEAN indicates whether the IRQ came from us (TRUE) or not (FALSE)
1319 * @param interrupt Interrupt that was triggered.
1320 * @param serviceContext Context specific pointer.
1321 */
1322BOOLEAN VBoxGuestIsrHandler(PKINTERRUPT interrupt, PVOID serviceContext)
1323{
1324 NTSTATUS rc;
1325 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)serviceContext;
1326 BOOLEAN fIRQTaken = FALSE;
1327
1328 dprintf(("VBoxGuest::VBoxGuestIsrHandler haveEvents = %d\n",
1329 pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents));
1330
1331 /*
1332 * now we have to find out whether it was our IRQ. Read the event mask
1333 * from our device to see if there are any pending events
1334 */
1335 if (pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents)
1336 {
1337 /* Acknowlegde events. */
1338 VMMDevEvents *req = pDevExt->irqAckEvents;
1339
1340 rc = VbglGRPerform (&req->header);
1341 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
1342 {
1343 dprintf(("VBoxGuest::VBoxGuestIsrHandler: acknowledge events succeeded %#x\n",
1344 req->events));
1345
1346 ASMAtomicOrU32((uint32_t *)&pDevExt->u32Events, req->events);
1347 IoRequestDpc(pDevExt->deviceObject, pDevExt->currentIrp, NULL);
1348 }
1349 else
1350 {
1351 /* This can't be actually. This is sign of a serious problem. */
1352 dprintf(("VBoxGuest::VBoxGuestIsrHandler: "
1353 "acknowledge events failed rc = %d, header rc = %d\n",
1354 rc, req->header.rc));
1355 }
1356
1357 /* Mark IRQ as taken, there were events for us. */
1358 fIRQTaken = TRUE;
1359 }
1360
1361 return fIRQTaken;
1362}
1363
1364/**
1365 * Worker thread to do periodic things such as synchronize the
1366 * system time and notify other drivers of events.
1367 *
1368 * @param pDevExt device extension pointer
1369 */
1370VOID vboxWorkerThread(PVOID context)
1371{
1372 PVBOXGUESTDEVEXT pDevExt;
1373
1374 pDevExt = (PVBOXGUESTDEVEXT)context;
1375 dprintf(("VBoxGuest::vboxWorkerThread entered\n"));
1376
1377 VMMDevReqHostTime *req = NULL;
1378
1379 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHostTime), VMMDevReq_GetHostTime);
1380
1381 if (RT_FAILURE(rc))
1382 {
1383 dprintf(("VBoxGuest::vboxWorkerThread: could not allocate request buffer, exiting rc = %d!\n", rc));
1384 return;
1385 }
1386
1387 /* perform the hypervisor address space reservation */
1388 reserveHypervisorMemory(pDevExt);
1389
1390 do
1391 {
1392 /*
1393 * Do the time sync
1394 */
1395 {
1396 LARGE_INTEGER systemTime;
1397 #define TICKSPERSEC 10000000
1398 #define TICKSPERMSEC 10000
1399 #define SECSPERDAY 86400
1400 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (uint64_t)SECSPERDAY)
1401 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
1402
1403
1404 req->header.rc = VERR_GENERAL_FAILURE;
1405
1406 rc = VbglGRPerform (&req->header);
1407
1408 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
1409 {
1410 uint64_t hostTime = req->time;
1411
1412 // Windows was originally designed in 1601...
1413 systemTime.QuadPart = hostTime * (uint64_t)TICKSPERMSEC + (uint64_t)TICKS_1601_TO_1970;
1414 dprintf(("VBoxGuest::vboxWorkerThread: synching time with host time (msec/UTC): %llu\n", hostTime));
1415 ZwSetSystemTime(&systemTime, NULL);
1416 }
1417 else
1418 {
1419 dprintf(("VBoxGuest::PowerStateRequest: error performing request to VMMDev."
1420 "rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
1421 }
1422 }
1423
1424 /*
1425 * Go asleep unless we're supposed to terminate
1426 */
1427 if (!pDevExt->stopThread)
1428 {
1429 ULONG secWait = 60;
1430 dprintf(("VBoxGuest::vboxWorkerThread: waiting for %u seconds...\n", secWait));
1431 LARGE_INTEGER dueTime;
1432 dueTime.QuadPart = -10000 * 1000 * (int)secWait;
1433 if (KeWaitForSingleObject(&pDevExt->workerThreadRequest, Executive,
1434 KernelMode, FALSE, &dueTime) == STATUS_SUCCESS)
1435 {
1436 KeResetEvent(&pDevExt->workerThreadRequest);
1437 }
1438 }
1439 } while (!pDevExt->stopThread);
1440
1441 dprintf(("VBoxGuest::vboxWorkerThread: we've been asked to terminate!\n"));
1442
1443 /* free our request buffer */
1444 VbglGRFree (&req->header);
1445
1446 if (pDevExt->workerThread)
1447 {
1448 ObDereferenceObject(pDevExt->workerThread);
1449 pDevExt->workerThread = NULL;
1450 }
1451 dprintf(("VBoxGuest::vboxWorkerThread: now really gone!\n"));
1452}
1453
1454/**
1455 * Create driver worker threads
1456 *
1457 * @returns NTSTATUS NT status code
1458 * @param pDevExt VBoxGuest device extension
1459 */
1460NTSTATUS createThreads(PVBOXGUESTDEVEXT pDevExt)
1461{
1462 NTSTATUS rc;
1463 HANDLE threadHandle;
1464 OBJECT_ATTRIBUTES objAttributes;
1465
1466 dprintf(("VBoxGuest::createThreads\n"));
1467
1468 // first setup the request semaphore
1469 KeInitializeEvent(&pDevExt->workerThreadRequest, SynchronizationEvent, FALSE);
1470
1471// the API has slightly changed after NT4
1472#ifdef TARGET_NT4
1473#ifdef OBJ_KERNEL_HANDLE
1474#undef OBJ_KERNEL_HANDLE
1475#endif
1476#define OBJ_KERNEL_HANDLE 0
1477#endif
1478
1479 /*
1480 * The worker thread
1481 */
1482 InitializeObjectAttributes(&objAttributes,
1483 NULL,
1484 OBJ_KERNEL_HANDLE,
1485 NULL,
1486 NULL);
1487
1488 rc = PsCreateSystemThread(&threadHandle,
1489 THREAD_ALL_ACCESS,
1490 &objAttributes,
1491 (HANDLE)0L,
1492 NULL,
1493 vboxWorkerThread,
1494 pDevExt);
1495 dprintf(("VBoxGuest::createThreads: PsCreateSystemThread for worker thread returned: 0x%x\n", rc));
1496 rc = ObReferenceObjectByHandle(threadHandle,
1497 THREAD_ALL_ACCESS,
1498 NULL,
1499 KernelMode,
1500 (PVOID*)&pDevExt->workerThread,
1501 NULL);
1502 ZwClose(threadHandle);
1503
1504 /*
1505 * The idle thread
1506 */
1507#if 0 /// @todo Windows "sees" that time is lost and reports 100% usage
1508 rc = PsCreateSystemThread(&threadHandle,
1509 THREAD_ALL_ACCESS,
1510 &objAttributes,
1511 (HANDLE)0L,
1512 NULL,
1513 vboxIdleThread,
1514 pDevExt);
1515 dprintf(("VBoxGuest::createThreads: PsCreateSystemThread for idle thread returned: 0x%x\n", rc));
1516 rc = ObReferenceObjectByHandle(threadHandle,
1517 THREAD_ALL_ACCESS,
1518 NULL,
1519 KernelMode,
1520 (PVOID*)&pDevExt->idleThread,
1521 NULL);
1522 ZwClose(threadHandle);
1523#endif
1524
1525 return rc;
1526}
1527
1528/**
1529 * Helper routine to reserve address space for the hypervisor
1530 * and communicate its position.
1531 *
1532 * @param pDevExt Device extension structure.
1533 */
1534VOID reserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt)
1535{
1536 // @todo rc handling
1537 uint32_t hypervisorSize;
1538
1539 VMMDevReqHypervisorInfo *req = NULL;
1540
1541 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_GetHypervisorInfo);
1542
1543 if (RT_SUCCESS(rc))
1544 {
1545 req->hypervisorStart = 0;
1546 req->hypervisorSize = 0;
1547
1548 rc = VbglGRPerform (&req->header);
1549
1550 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
1551 {
1552 hypervisorSize = req->hypervisorSize;
1553
1554 if (!hypervisorSize)
1555 {
1556 dprintf(("VBoxGuest::reserveHypervisorMemory: host returned 0, not doing anything\n"));
1557 return;
1558 }
1559
1560 dprintf(("VBoxGuest::reserveHypervisorMemory: host wants %u bytes of hypervisor address space\n", hypervisorSize));
1561
1562 // Map fictive physical memory into the kernel address space to reserve virtual
1563 // address space. This API does not perform any checks but just allocate the
1564 // PTEs (which we don't really need/want but there isn't any other clean method).
1565 // The hypervisor only likes 4MB aligned virtual addresses, so we have to allocate
1566 // 4MB more than we are actually supposed to in order to guarantee that. Maybe we
1567 // can come up with a less lavish algorithm lateron.
1568 PHYSICAL_ADDRESS physAddr;
1569 physAddr.QuadPart = HYPERVISOR_PHYSICAL_START;
1570 pDevExt->hypervisorMappingSize = hypervisorSize + 0x400000;
1571 pDevExt->hypervisorMapping = MmMapIoSpace(physAddr,
1572 pDevExt->hypervisorMappingSize,
1573 MmNonCached);
1574 if (!pDevExt->hypervisorMapping)
1575 {
1576 dprintf(("VBoxGuest::reserveHypervisorMemory: MmMapIoSpace returned NULL!\n"));
1577 return;
1578 }
1579
1580 dprintf(("VBoxGuest::reserveHypervisorMemory: MmMapIoSpace returned %p\n", pDevExt->hypervisorMapping));
1581 dprintf(("VBoxGuest::reserveHypervisorMemory: communicating %p to host\n",
1582 RT_ALIGN_P(pDevExt->hypervisorMapping, 0x400000)));
1583
1584 /* align at 4MB */
1585 req->hypervisorStart = (RTGCPTR)RT_ALIGN_P(pDevExt->hypervisorMapping, 0x400000);
1586
1587 req->header.requestType = VMMDevReq_SetHypervisorInfo;
1588 req->header.rc = VERR_GENERAL_FAILURE;
1589
1590 /* issue request */
1591 rc = VbglGRPerform (&req->header);
1592
1593 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
1594 {
1595 dprintf(("VBoxGuest::reserveHypervisorMemory: error communicating physical address to VMMDev!"
1596 "rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
1597 }
1598 }
1599 else
1600 {
1601 dprintf(("VBoxGuest::reserveHypervisorMemory: request failed with rc %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
1602 }
1603 VbglGRFree (&req->header);
1604 }
1605
1606 return;
1607}
1608
1609/**
1610 * Helper function to unregister a virtual address space mapping
1611 *
1612 * @param pDevExt Device extension
1613 */
1614VOID unreserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt)
1615{
1616 VMMDevReqHypervisorInfo *req = NULL;
1617
1618 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_SetHypervisorInfo);
1619
1620 if (RT_SUCCESS(rc))
1621 {
1622 /* tell the hypervisor that the mapping is no longer available */
1623
1624 req->hypervisorStart = 0;
1625 req->hypervisorSize = 0;
1626
1627 rc = VbglGRPerform (&req->header);
1628
1629 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
1630 {
1631 dprintf(("VBoxGuest::unreserveHypervisorMemory: error communicating physical address to VMMDev!"
1632 "rc = %d, VMMDev rc = %Rrc\n", rc, req->header.rc));
1633 }
1634
1635 VbglGRFree (&req->header);
1636 }
1637
1638 if (!pDevExt->hypervisorMapping)
1639 {
1640 dprintf(("VBoxGuest::unreserveHypervisorMemory: there is no mapping, returning\n"));
1641 return;
1642 }
1643
1644 // unmap fictive IO space
1645 MmUnmapIoSpace(pDevExt->hypervisorMapping, pDevExt->hypervisorMappingSize);
1646 dprintf(("VBoxGuest::unreserveHypervisorMemmory: done\n"));
1647}
1648
1649/**
1650 * Idle thread that runs at the lowest priority possible
1651 * and whenever scheduled, makes a VMMDev call to give up
1652 * timeslices. This is so prevent Windows from thinking that
1653 * nothing is happening on the machine and doing stupid things
1654 * that would steal time from other VMs it doesn't know of.
1655 *
1656 * @param pDevExt device extension pointer
1657 */
1658VOID vboxIdleThread(PVOID context)
1659{
1660 PVBOXGUESTDEVEXT pDevExt;
1661
1662 pDevExt = (PVBOXGUESTDEVEXT)context;
1663 dprintf(("VBoxGuest::vboxIdleThread entered\n"));
1664
1665 /* set priority as low as possible */
1666 KeSetPriorityThread(KeGetCurrentThread(), LOW_PRIORITY);
1667
1668 /* allocate VMMDev request structure */
1669 VMMDevReqIdle *req;
1670 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_Idle);
1671 if (RT_FAILURE(rc))
1672 {
1673 dprintf(("VBoxGuest::vboxIdleThread: error %Rrc allocating request structure!\n"));
1674 return;
1675 }
1676
1677 do
1678 {
1679 //dprintf(("VBoxGuest: performing idle request..\n"));
1680 /* perform idle request */
1681 VbglGRPerform(&req->header);
1682
1683 } while (!pDevExt->stopThread);
1684
1685 VbglGRFree(&req->header);
1686
1687 dprintf(("VBoxGuest::vboxIdleThread leaving\n"));
1688}
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