VirtualBox

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

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

todo added

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