VirtualBox

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

最後變更 在這個檔案從8776是 8776,由 vboxsync 提交於 17 年 前

HGCM wait for a request completion must be not alertable (Windows guest).

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

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