VirtualBox

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

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

A IRP_MJ_SYSTEM_CONTROL handler is required.

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