VirtualBox

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

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

Must pass on IRP_MJ_SYSTEM_CONTROL to the next driver in the chain.

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