VirtualBox

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

Last change on this file since 22683 was 21888, checked in by vboxsync, 16 years ago

Additions/WINNT: fix problems of the mouse cursor not being shown when mouse integration is enabled or disabled

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