VirtualBox

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

Last change on this file since 1355 was 1355, checked in by vboxsync, 18 years ago

nc

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