VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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