VirtualBox

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

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

Updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.5 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 /* just perform the request */
433 VMMDevGetMemBalloonChangeRequest *req = NULL;
434
435 dprintf(("VBoxGuestQueryMemoryBalloon\n"));
436
437 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, sizeof(VMMDevGetMemBalloonChangeRequest), VMMDevReq_GetMemBalloonChangeRequest);
438 vmmdevInitRequest(&req->header, VMMDevReq_GetMemBalloonChangeRequest);
439 req->eventAck = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
440
441 if (VBOX_SUCCESS(rc))
442 {
443 rc = VbglGRPerform(&req->header);
444
445 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
446 {
447 dprintf(("VBoxGuest::VBoxGuestDeviceControl IOCTL_VBOXGUEST_CTL_CHECK_BALLOON: error issuing request to VMMDev!"
448 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
449 }
450 else
451 {
452
453 }
454
455 VbglGRFree(&req->header);
456 }
457 return rc;
458}
459
460
461/**
462 * Device I/O Control entry point.
463 *
464 * @param pDevObj Device object.
465 * @param pIrp Request packet.
466 */
467NTSTATUS VBoxGuestDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
468{
469 dprintf(("VBoxGuest::VBoxGuestDeviceControl\n"));
470
471 NTSTATUS Status = STATUS_SUCCESS;
472
473 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
474
475 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
476
477 char *pBuf = (char *)pIrp->AssociatedIrp.SystemBuffer; /* all requests are buffered. */
478
479 unsigned cbOut = 0;
480
481 switch (pStack->Parameters.DeviceIoControl.IoControlCode)
482 {
483 case IOCTL_VBOXGUEST_GETVMMDEVPORT:
484 {
485 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_GETVMMDEVPORT\n"));
486
487 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof (VBoxGuestPortInfo))
488 {
489 Status = STATUS_BUFFER_TOO_SMALL;
490 break;
491 }
492
493 VBoxGuestPortInfo *portInfo = (VBoxGuestPortInfo*)pBuf;
494
495 portInfo->portAddress = pDevExt->startPortAddress;
496 portInfo->pVMMDevMemory = pDevExt->pVMMDevMemory;
497
498 cbOut = sizeof(VBoxGuestPortInfo);
499
500 break;
501 }
502
503 case IOCTL_VBOXGUEST_WAITEVENT:
504 {
505 /* Need to be extended to support multiple waiters for an event,
506 * array of counters for each event, event mask is computed, each
507 * time a wait event is arrived.
508 */
509 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_WAITEVENT\n"));
510
511 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VBoxGuestWaitEventInfo))
512 {
513 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d < sizeof(VBoxGuestWaitEventInfo)\n",
514 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestWaitEventInfo)));
515 Status = STATUS_BUFFER_TOO_SMALL;
516 break;
517 }
518
519 if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VBoxGuestWaitEventInfo)) {
520 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < sizeof(VBoxGuestWaitEventInfo)\n",
521 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestWaitEventInfo)));
522 Status = STATUS_BUFFER_TOO_SMALL;
523 break;
524 }
525
526 VBoxGuestWaitEventInfo *eventInfo = (VBoxGuestWaitEventInfo *)pBuf;
527
528 if (!eventInfo->u32EventMaskIn || !IsPowerOfTwo (eventInfo->u32EventMaskIn)) {
529 dprintf (("VBoxGuest::VBoxGuestDeviceControl: Invalid input mask %#x\n",
530 eventInfo->u32EventMaskIn));
531 Status = STATUS_INVALID_PARAMETER;
532 break;
533 }
534
535 eventInfo->u32EventFlagsOut = 0;
536 int iBitOffset = GetMsb32 (eventInfo->u32EventMaskIn);
537
538 dprintf (("mask = %d, iBitOffset = %d\n", iBitOffset, eventInfo->u32EventMaskIn));
539
540 LARGE_INTEGER timeout;
541 timeout.QuadPart = eventInfo->u32TimeoutIn;
542 timeout.QuadPart *= -100000;
543
544 NTSTATUS rc = STATUS_SUCCESS;
545
546 for (;;)
547 {
548 // following code is subject to "lost wakeup" bug
549 // -- malc
550 bool fEventPending = TestAndClearEvent (pDevExt, iBitOffset);
551 if (fEventPending)
552 {
553 eventInfo->u32EventFlagsOut = 1 << iBitOffset;
554 break;
555 }
556
557 rc = KeWaitForSingleObject (&pDevExt->keventNotification, Executive /** @todo UserRequest? */,
558 KernelMode, TRUE,
559 eventInfo->u32TimeoutIn == ~0L ? NULL : &timeout);
560 dprintf(("IOCTL_VBOXGUEST_WAITEVENT: Wait returned %d -> event %x\n", rc, eventInfo->u32EventFlagsOut));
561
562 if (rc != STATUS_SUCCESS)
563 {
564 /* There was a timeout or wait was interrupted, etc. */
565 break;
566 }
567 }
568
569 dprintf (("u32EventFlagsOut = %#x\n", eventInfo->u32EventFlagsOut));
570 cbOut = sizeof(VBoxGuestWaitEventInfo);
571 break;
572 }
573
574 case IOCTL_VBOXGUEST_VMMREQUEST:
575 {
576 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_VMMREQUEST\n"));
577
578#define CHECK_SIZE(s) \
579 if (pStack->Parameters.DeviceIoControl.OutputBufferLength < s) \
580 { \
581 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d < %d\n", \
582 pStack->Parameters.DeviceIoControl.OutputBufferLength, s)); \
583 Status = STATUS_BUFFER_TOO_SMALL; \
584 break; \
585 } \
586 if (pStack->Parameters.DeviceIoControl.InputBufferLength < s) { \
587 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < %d\n", \
588 pStack->Parameters.DeviceIoControl.InputBufferLength, s)); \
589 Status = STATUS_BUFFER_TOO_SMALL; \
590 break; \
591 }
592
593 /* get the request header */
594 CHECK_SIZE(sizeof(VMMDevRequestHeader));
595 VMMDevRequestHeader *requestHeader = (VMMDevRequestHeader *)pBuf;
596 if (!vmmdevGetRequestSize(requestHeader->requestType))
597 {
598 Status = STATUS_INVALID_PARAMETER;
599 break;
600 }
601 /* make sure the buffers suit the request */
602 CHECK_SIZE(vmmdevGetRequestSize(requestHeader->requestType));
603
604 /* just perform the request */
605 VMMDevRequestHeader *req = NULL;
606
607 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, requestHeader->size, requestHeader->requestType);
608
609 if (VBOX_SUCCESS(rc))
610 {
611 /* copy the request information */
612 memcpy((void*)req, (void*)pBuf, requestHeader->size);
613 rc = VbglGRPerform(req);
614
615 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->rc))
616 {
617 dprintf(("VBoxGuest::VBoxGuestDeviceControl IOCTL_VBOXGUEST_VMMREQUEST: error issuing request to VMMDev!"
618 "rc = %d, VMMDev rc = %Vrc\n", rc, req->rc));
619 Status = STATUS_UNSUCCESSFUL;
620 }
621 else
622 {
623 /* copy result */
624 memcpy((void*)pBuf, (void*)req, requestHeader->size);
625 cbOut = requestHeader->size;
626 }
627
628 VbglGRFree(req);
629 }
630 else
631 {
632 Status = STATUS_UNSUCCESSFUL;
633 }
634#undef CHECK_SIZE
635 break;
636 }
637
638 case IOCTL_VBOXGUEST_CTL_FILTER_MASK:
639 {
640 VBoxGuestFilterMaskInfo *maskInfo;
641
642 if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VBoxGuestFilterMaskInfo)) {
643 dprintf (("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d < %d\n",
644 pStack->Parameters.DeviceIoControl.InputBufferLength,
645 sizeof (VBoxGuestFilterMaskInfo)));
646 Status = STATUS_BUFFER_TOO_SMALL;
647 break;
648
649 }
650
651 maskInfo = (VBoxGuestFilterMaskInfo *) pBuf;
652 if (!CtlGuestFilterMask (maskInfo->u32OrMask, maskInfo->u32NotMask))
653 {
654 Status = STATUS_UNSUCCESSFUL;
655 }
656 break;
657 }
658
659#ifdef VBOX_HGCM
660 /* HGCM offers blocking IOCTLSs just like waitevent and actually
661 * uses the same waiting code.
662 */
663 case IOCTL_VBOXGUEST_HGCM_CONNECT:
664 {
665 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_HGCM_CONNECT\n"));
666
667 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(VBoxGuestHGCMConnectInfo))
668 {
669 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(VBoxGuestHGCMConnectInfo) %d\n",
670 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestHGCMConnectInfo)));
671 Status = STATUS_INVALID_PARAMETER;
672 break;
673 }
674
675 if (pStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(VBoxGuestHGCMConnectInfo)) {
676 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d != sizeof(VBoxGuestHGCMConnectInfo) %d\n",
677 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestHGCMConnectInfo)));
678 Status = STATUS_INVALID_PARAMETER;
679 break;
680 }
681
682 VBoxGuestHGCMConnectInfo *ptr = (VBoxGuestHGCMConnectInfo *)pBuf;
683
684 /* If request will be processed asynchronously, execution will
685 * go to VBoxHGCMCallback. There it will wait for the request event, signalled from IRQ.
686 * On IRQ arrival, the VBoxHGCMCallback(s) will check the request memory and, if completion
687 * flag is set, returns.
688 */
689
690 dprintf(("a) ptr->u32ClientID = %d\n", ptr->u32ClientID));
691
692 int rc = VbglHGCMConnect (ptr, VBoxHGCMCallback, pDevExt, 0);
693
694 dprintf(("b) ptr->u32ClientID = %d\n", ptr->u32ClientID));
695
696 if (VBOX_FAILURE(rc))
697 {
698 dprintf(("IOCTL_VBOXGUEST_HGCM_CONNECT: vbox rc = %Vrc\n", rc));
699 Status = STATUS_UNSUCCESSFUL;
700 }
701 else
702 {
703 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
704 }
705
706 } break;
707
708 case IOCTL_VBOXGUEST_HGCM_DISCONNECT:
709 {
710 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_HGCM_DISCONNECT\n"));
711
712 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(VBoxGuestHGCMDisconnectInfo))
713 {
714 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(VBoxGuestHGCMDisconnectInfo) %d\n",
715 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(VBoxGuestHGCMDisconnectInfo)));
716 Status = STATUS_INVALID_PARAMETER;
717 break;
718 }
719
720 if (pStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(VBoxGuestHGCMDisconnectInfo)) {
721 dprintf(("VBoxGuest::VBoxGuestDeviceControl: InputBufferLength %d != sizeof(VBoxGuestHGCMDisconnectInfo) %d\n",
722 pStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(VBoxGuestHGCMDisconnectInfo)));
723 Status = STATUS_INVALID_PARAMETER;
724 break;
725 }
726
727 VBoxGuestHGCMDisconnectInfo *ptr = (VBoxGuestHGCMDisconnectInfo *)pBuf;
728
729 /* If request will be processed asynchronously, execution will
730 * go to VBoxHGCMCallback. There it will wait for the request event, signalled from IRQ.
731 * On IRQ arrival, the VBoxHGCMCallback(s) will check the request memory and, if completion
732 * flag is set, returns.
733 */
734
735 int rc = VbglHGCMDisconnect (ptr, VBoxHGCMCallback, pDevExt, 0);
736
737 if (VBOX_FAILURE(rc))
738 {
739 dprintf(("IOCTL_VBOXGUEST_HGCM_DISCONNECT: vbox rc = %Vrc\n", rc));
740 Status = STATUS_UNSUCCESSFUL;
741 }
742 else
743 {
744 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
745 }
746
747 } break;
748
749 case IOCTL_VBOXGUEST_HGCM_CALL:
750 {
751 dprintf(("VBoxGuest::VBoxGuestDeviceControl: IOCTL_VBOXGUEST_HGCM_CALL\n"));
752
753 Status = vboxHGCMVerifyIOBuffers (pStack,
754 sizeof (VBoxGuestHGCMCallInfo));
755
756 if (Status != STATUS_SUCCESS)
757 {
758 dprintf(("VBoxGuest::VBoxGuestDeviceControl: invalid parameter. Status: %p\n", Status));
759 break;
760 }
761
762 VBoxGuestHGCMCallInfo *ptr = (VBoxGuestHGCMCallInfo *)pBuf;
763
764 int rc = VbglHGCMCall (ptr, VBoxHGCMCallback, pDevExt, 0);
765
766 if (VBOX_FAILURE(rc))
767 {
768 dprintf(("IOCTL_VBOXGUEST_HGCM_CALL: vbox rc = %Vrc\n", rc));
769 Status = STATUS_UNSUCCESSFUL;
770 }
771 else
772 {
773 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
774 }
775
776 } break;
777#endif /* VBOX_HGCM */
778
779#ifdef VBOX_WITH_VRDP_SESSION_HANDLING
780 case IOCTL_VBOXGUEST_ENABLE_VRDP_SESSION:
781 {
782 if (!pDevExt->fVRDPEnabled)
783 {
784 KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
785
786 pDevExt->fVRDPEnabled = TRUE;
787 pDevExt->ulOldActiveConsoleId = pSharedUserData->ActiveConsoleId;
788 pSharedUserData->ActiveConsoleId = 2;
789 }
790 break;
791 }
792
793 case IOCTL_VBOXGUEST_DISABLE_VRDP_SESSION:
794 {
795 if (pDevExt->fVRDPEnabled)
796 {
797 KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
798
799 pDevExt->fVRDPEnabled = FALSE;
800 pSharedUserData->ActiveConsoleId = pDevExt->ulOldActiveConsoleId;
801 pDevExt->ulOldActiveConsoleId = 0;
802 }
803 break;
804 }
805#endif
806
807#ifdef VBOX_WITH_MANAGEMENT
808 case IOCTL_VBOXGUEST_CTL_CHECK_BALLOON:
809 {
810 ULONG *pMemBalloonSize = (ULONG *) pBuf;
811
812 if (pStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
813 {
814 dprintf(("VBoxGuest::VBoxGuestDeviceControl: OutputBufferLength %d != sizeof(ULONG) %d\n",
815 pStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(ULONG)));
816 Status = STATUS_INVALID_PARAMETER;
817 break;
818 }
819
820 int rc = VBoxGuestQueryMemoryBalloon(pDevExt, pMemBalloonSize);
821 if (VBOX_FAILURE(rc))
822 {
823 dprintf(("IOCTL_VBOXGUEST_CTL_CHECK_BALLOON: vbox rc = %Vrc\n", rc));
824 Status = STATUS_UNSUCCESSFUL;
825 }
826 else
827 {
828 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
829 }
830 break;
831 }
832#endif
833
834 default:
835 Status = STATUS_INVALID_PARAMETER;
836 break;
837 }
838
839 pIrp->IoStatus.Status = Status;
840 pIrp->IoStatus.Information = cbOut;
841
842 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
843
844 dprintf(("VBoxGuest::VBoxGuestDeviceControl: returned cbOut=%d rc=%#x\n", cbOut, Status));
845
846 return Status;
847}
848
849
850/**
851 * IRP_MJ_SYSTEM_CONTROL handler
852 *
853 * @returns NT status code
854 * @param pDevObj Device object.
855 * @param pIrp IRP.
856 */
857NTSTATUS VBoxGuestSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
858{
859 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
860
861 dprintf(("VBoxGuest::VBoxGuestSystemControl\n"));
862
863 /* Always pass it on to the next driver. */
864 IoSkipCurrentIrpStackLocation(pIrp);
865
866 return IoCallDriver(pDevExt->nextLowerDriver, pIrp);
867}
868
869/**
870 * IRP_MJ_SHUTDOWN handler
871 *
872 * @returns NT status code
873 * @param pDevObj Device object.
874 * @param pIrp IRP.
875 */
876NTSTATUS VBoxGuestShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
877{
878 VMMDevPowerStateRequest *req = NULL;
879
880 dprintf(("VBoxGuest::VBoxGuestShutdown\n"));
881
882 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
883
884 if (VBOX_SUCCESS(rc))
885 {
886 req->powerState = VMMDevPowerState_PowerOff;
887
888 rc = VbglGRPerform (&req->header);
889
890 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
891 {
892 dprintf(("VBoxGuest::PowerStateRequest: error performing request to VMMDev."
893 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
894 }
895
896 VbglGRFree (&req->header);
897 }
898
899 return STATUS_SUCCESS;
900}
901
902/**
903 * Stub function for functions we don't implemented.
904 *
905 * @returns STATUS_NOT_SUPPORTED
906 * @param pDevObj Device object.
907 * @param pIrp IRP.
908 */
909NTSTATUS VBoxGuestNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
910{
911 dprintf(("VBoxGuest::VBoxGuestNotSupportedStub\n"));
912 pDevObj = pDevObj;
913
914 pIrp->IoStatus.Information = 0;
915 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
916 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
917
918 return STATUS_NOT_SUPPORTED;
919}
920
921/**
922 * DPC handler
923 *
924 * @param dpc DPC descriptor.
925 * @param pDevObj Device object.
926 * @param irp Interrupt request packet.
927 * @param context Context specific pointer.
928 */
929VOID VBoxGuestDpcHandler(PKDPC dpc, PDEVICE_OBJECT pDevObj,
930 PIRP irp, PVOID context)
931{
932 /* Unblock handlers waiting for arrived events.
933 *
934 * Events are very low things, there is one event flag (1 or more bit)
935 * for each event. Each event is processed by exactly one handler.
936 *
937 * Assume that we trust additions and that other drivers will
938 * handle its respective events without trying to fetch all events.
939 *
940 * Anyway design assures that wrong event processing will affect only guest.
941 *
942 * Event handler calls VMMDev IOCTL for waiting an event.
943 * It supplies event mask. IOCTL blocks on EventNotification.
944 * Here we just signal an the EventNotification to all waiting
945 * threads, the IOCTL handler analyzes events and either
946 * return to caller or blocks again.
947 *
948 * If we do not have too many events this is a simple and good
949 * approach. Other way is to have as many Event objects as the callers
950 * and wake up only callers waiting for the specific event.
951 *
952 * Now with the 'wake up all' appoach we probably do not need the DPC
953 * handler and can signal event directly from ISR.
954 *
955 */
956
957 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
958
959 dprintf(("VBoxGuest::VBoxGuestDpcHandler\n"));
960
961 KePulseEvent(&pDevExt->keventNotification, 0, FALSE);
962
963}
964
965/**
966 * ISR handler
967 *
968 * @return BOOLEAN indicates whether the IRQ came from us (TRUE) or not (FALSE)
969 * @param interrupt Interrupt that was triggered.
970 * @param serviceContext Context specific pointer.
971 */
972BOOLEAN VBoxGuestIsrHandler(PKINTERRUPT interrupt, PVOID serviceContext)
973{
974 NTSTATUS rc;
975 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)serviceContext;
976 BOOLEAN fIRQTaken = FALSE;
977
978 dprintf(("VBoxGuest::VBoxGuestIsrHandler haveEvents = %d\n",
979 pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents));
980
981 /*
982 * now we have to find out whether it was our IRQ. Read the event mask
983 * from our device to see if there are any pending events
984 */
985 if (pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents)
986 {
987 /* Acknowlegde events. */
988 VMMDevEvents *req = pDevExt->irqAckEvents;
989
990 rc = VbglGRPerform (&req->header);
991 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
992 {
993 dprintf(("VBoxGuest::VBoxGuestIsrHandler: acknowledge events succeeded %#x\n",
994 req->events));
995
996 ASMAtomicOrU32((uint32_t *)&pDevExt->u32Events, req->events);
997 IoRequestDpc(pDevExt->deviceObject, pDevExt->currentIrp, NULL);
998 }
999 else
1000 {
1001 /* This can't be actually. This is sign of a serious problem. */
1002 dprintf(("VBoxGuest::VBoxGuestIsrHandler: "
1003 "acknowledge events failed rc = %d, header rc = %d\n",
1004 rc, req->header.rc));
1005 }
1006
1007 /* Mark IRQ as taken, there were events for us. */
1008 fIRQTaken = TRUE;
1009 }
1010
1011 return fIRQTaken;
1012}
1013
1014/**
1015 * Worker thread to do periodic things such as synchronize the
1016 * system time and notify other drivers of events.
1017 *
1018 * @param pDevExt device extension pointer
1019 */
1020VOID vboxWorkerThread(PVOID context)
1021{
1022 PVBOXGUESTDEVEXT pDevExt;
1023
1024 pDevExt = (PVBOXGUESTDEVEXT)context;
1025 dprintf(("VBoxGuest::vboxWorkerThread entered\n"));
1026
1027 VMMDevReqHostTime *req = NULL;
1028
1029 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHostTime), VMMDevReq_GetHostTime);
1030
1031 if (VBOX_FAILURE(rc))
1032 {
1033 dprintf(("VBoxGuest::vboxWorkerThread: could not allocate request buffer, exiting rc = %d!\n", rc));
1034 return;
1035 }
1036
1037 /* perform the hypervisor address space reservation */
1038 reserveHypervisorMemory(pDevExt);
1039
1040 do
1041 {
1042 /*
1043 * Do the time sync
1044 */
1045 {
1046 LARGE_INTEGER systemTime;
1047 #define TICKSPERSEC 10000000
1048 #define TICKSPERMSEC 10000
1049 #define SECSPERDAY 86400
1050 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (uint64_t)SECSPERDAY)
1051 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
1052
1053
1054 req->header.rc = VERR_GENERAL_FAILURE;
1055
1056 rc = VbglGRPerform (&req->header);
1057
1058 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
1059 {
1060 uint64_t hostTime = req->time;
1061
1062 // Windows was originally designed in 1601...
1063 systemTime.QuadPart = hostTime * (uint64_t)TICKSPERMSEC + (uint64_t)TICKS_1601_TO_1970;
1064 dprintf(("VBoxGuest::vboxWorkerThread: synching time with host time (msec/UTC): %llu\n", hostTime));
1065 ZwSetSystemTime(&systemTime, NULL);
1066 }
1067 else
1068 {
1069 dprintf(("VBoxGuest::PowerStateRequest: error performing request to VMMDev."
1070 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
1071 }
1072 }
1073
1074 /*
1075 * Go asleep unless we're supposed to terminate
1076 */
1077 if (!pDevExt->stopThread)
1078 {
1079 ULONG secWait = 60;
1080 dprintf(("VBoxGuest::vboxWorkerThread: waiting for %u seconds...\n", secWait));
1081 LARGE_INTEGER dueTime;
1082 dueTime.QuadPart = -10000 * 1000 * (int)secWait;
1083 if (KeWaitForSingleObject(&pDevExt->workerThreadRequest, Executive,
1084 KernelMode, FALSE, &dueTime) == STATUS_SUCCESS)
1085 {
1086 KeResetEvent(&pDevExt->workerThreadRequest);
1087 }
1088 }
1089 } while (!pDevExt->stopThread);
1090
1091 dprintf(("VBoxGuest::vboxWorkerThread: we've been asked to terminate!\n"));
1092
1093 /* free our request buffer */
1094 VbglGRFree (&req->header);
1095
1096 if (pDevExt->workerThread)
1097 {
1098 ObDereferenceObject(pDevExt->workerThread);
1099 pDevExt->workerThread = NULL;
1100 }
1101 dprintf(("VBoxGuest::vboxWorkerThread: now really gone!\n"));
1102}
1103
1104/**
1105 * Create driver worker threads
1106 *
1107 * @returns NTSTATUS NT status code
1108 * @param pDevExt VBoxGuest device extension
1109 */
1110NTSTATUS createThreads(PVBOXGUESTDEVEXT pDevExt)
1111{
1112 NTSTATUS rc;
1113 HANDLE threadHandle;
1114 OBJECT_ATTRIBUTES objAttributes;
1115
1116 dprintf(("VBoxGuest::createThreads\n"));
1117
1118 // first setup the request semaphore
1119 KeInitializeEvent(&pDevExt->workerThreadRequest, SynchronizationEvent, FALSE);
1120
1121// the API has slightly changed after NT4
1122#ifdef TARGET_NT4
1123#ifdef OBJ_KERNEL_HANDLE
1124#undef OBJ_KERNEL_HANDLE
1125#endif
1126#define OBJ_KERNEL_HANDLE 0
1127#endif
1128
1129 /*
1130 * The worker thread
1131 */
1132 InitializeObjectAttributes(&objAttributes,
1133 NULL,
1134 OBJ_KERNEL_HANDLE,
1135 NULL,
1136 NULL);
1137
1138 rc = PsCreateSystemThread(&threadHandle,
1139 THREAD_ALL_ACCESS,
1140 &objAttributes,
1141 (HANDLE)0L,
1142 NULL,
1143 vboxWorkerThread,
1144 pDevExt);
1145 dprintf(("VBoxGuest::createThreads: PsCreateSystemThread for worker thread returned: 0x%x\n", rc));
1146 rc = ObReferenceObjectByHandle(threadHandle,
1147 THREAD_ALL_ACCESS,
1148 NULL,
1149 KernelMode,
1150 (PVOID*)&pDevExt->workerThread,
1151 NULL);
1152 ZwClose(threadHandle);
1153
1154 /*
1155 * The idle thread
1156 */
1157#if 0 /// @todo Windows "sees" that time is lost and reports 100% usage
1158 rc = PsCreateSystemThread(&threadHandle,
1159 THREAD_ALL_ACCESS,
1160 &objAttributes,
1161 (HANDLE)0L,
1162 NULL,
1163 vboxIdleThread,
1164 pDevExt);
1165 dprintf(("VBoxGuest::createThreads: PsCreateSystemThread for idle thread returned: 0x%x\n", rc));
1166 rc = ObReferenceObjectByHandle(threadHandle,
1167 THREAD_ALL_ACCESS,
1168 NULL,
1169 KernelMode,
1170 (PVOID*)&pDevExt->idleThread,
1171 NULL);
1172 ZwClose(threadHandle);
1173#endif
1174
1175 return rc;
1176}
1177
1178/**
1179 * Helper routine to reserve address space for the hypervisor
1180 * and communicate its position.
1181 *
1182 * @param pDevExt Device extension structure.
1183 */
1184VOID reserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt)
1185{
1186 // @todo rc handling
1187 uint32_t hypervisorSize;
1188
1189 VMMDevReqHypervisorInfo *req = NULL;
1190
1191 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_GetHypervisorInfo);
1192
1193 if (VBOX_SUCCESS(rc))
1194 {
1195 req->hypervisorStart = 0;
1196 req->hypervisorSize = 0;
1197
1198 rc = VbglGRPerform (&req->header);
1199
1200 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
1201 {
1202 hypervisorSize = req->hypervisorSize;
1203
1204 if (!hypervisorSize)
1205 {
1206 dprintf(("VBoxGuest::reserveHypervisorMemory: host returned 0, not doing anything\n"));
1207 return;
1208 }
1209
1210 dprintf(("VBoxGuest::reserveHypervisorMemory: host wants %u bytes of hypervisor address space\n", hypervisorSize));
1211
1212 // Map fictive physical memory into the kernel address space to reserve virtual
1213 // address space. This API does not perform any checks but just allocate the
1214 // PTEs (which we don't really need/want but there isn't any other clean method).
1215 // The hypervisor only likes 4MB aligned virtual addresses, so we have to allocate
1216 // 4MB more than we are actually supposed to in order to guarantee that. Maybe we
1217 // can come up with a less lavish algorithm lateron.
1218 PHYSICAL_ADDRESS physAddr;
1219 physAddr.QuadPart = HYPERVISOR_PHYSICAL_START;
1220 pDevExt->hypervisorMappingSize = hypervisorSize + 0x400000;
1221 pDevExt->hypervisorMapping = MmMapIoSpace(physAddr,
1222 pDevExt->hypervisorMappingSize,
1223 MmNonCached);
1224 if (!pDevExt->hypervisorMapping)
1225 {
1226 dprintf(("VBoxGuest::reserveHypervisorMemory: MmMapIoSpace returned NULL!\n"));
1227 return;
1228 }
1229
1230 dprintf(("VBoxGuest::reserveHypervisorMemory: MmMapIoSpace returned %p\n", pDevExt->hypervisorMapping));
1231 dprintf(("VBoxGuest::reserveHypervisorMemory: communicating %p to host\n",
1232 ALIGNP(pDevExt->hypervisorMapping, 0x400000)));
1233
1234 /* align at 4MB */
1235 req->hypervisorStart = (RTGCPTR)ALIGNP(pDevExt->hypervisorMapping, 0x400000);
1236
1237 req->header.requestType = VMMDevReq_SetHypervisorInfo;
1238 req->header.rc = VERR_GENERAL_FAILURE;
1239
1240 /* issue request */
1241 rc = VbglGRPerform (&req->header);
1242
1243 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
1244 {
1245 dprintf(("VBoxGuest::reserveHypervisorMemory: error communicating physical address to VMMDev!"
1246 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
1247 }
1248 }
1249 else
1250 {
1251 dprintf(("VBoxGuest::reserveHypervisorMemory: request failed with rc %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
1252 }
1253 VbglGRFree (&req->header);
1254 }
1255
1256 return;
1257}
1258
1259/**
1260 * Helper function to unregister a virtual address space mapping
1261 *
1262 * @param pDevExt Device extension
1263 */
1264VOID unreserveHypervisorMemory(PVBOXGUESTDEVEXT pDevExt)
1265{
1266 VMMDevReqHypervisorInfo *req = NULL;
1267
1268 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_SetHypervisorInfo);
1269
1270 if (VBOX_SUCCESS(rc))
1271 {
1272 /* tell the hypervisor that the mapping is no longer available */
1273
1274 req->hypervisorStart = 0;
1275 req->hypervisorSize = 0;
1276
1277 rc = VbglGRPerform (&req->header);
1278
1279 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
1280 {
1281 dprintf(("VBoxGuest::unreserveHypervisorMemory: error communicating physical address to VMMDev!"
1282 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
1283 }
1284
1285 VbglGRFree (&req->header);
1286 }
1287
1288 if (!pDevExt->hypervisorMapping)
1289 {
1290 dprintf(("VBoxGuest::unreserveHypervisorMemory: there is no mapping, returning\n"));
1291 return;
1292 }
1293
1294 // unmap fictive IO space
1295 MmUnmapIoSpace(pDevExt->hypervisorMapping, pDevExt->hypervisorMappingSize);
1296 dprintf(("VBoxGuest::unreserveHypervisorMemmory: done\n"));
1297}
1298
1299/**
1300 * Idle thread that runs at the lowest priority possible
1301 * and whenever scheduled, makes a VMMDev call to give up
1302 * timeslices. This is so prevent Windows from thinking that
1303 * nothing is happening on the machine and doing stupid things
1304 * that would steal time from other VMs it doesn't know of.
1305 *
1306 * @param pDevExt device extension pointer
1307 */
1308VOID vboxIdleThread(PVOID context)
1309{
1310 PVBOXGUESTDEVEXT pDevExt;
1311
1312 pDevExt = (PVBOXGUESTDEVEXT)context;
1313 dprintf(("VBoxGuest::vboxIdleThread entered\n"));
1314
1315 /* set priority as low as possible */
1316 KeSetPriorityThread(KeGetCurrentThread(), LOW_PRIORITY);
1317
1318 /* allocate VMMDev request structure */
1319 VMMDevReqIdle *req;
1320 int rc = VbglGRAlloc((VMMDevRequestHeader **)&req, sizeof (VMMDevReqHypervisorInfo), VMMDevReq_Idle);
1321 if (VBOX_FAILURE(rc))
1322 {
1323 dprintf(("VBoxGuest::vboxIdleThread: error %Vrc allocating request structure!\n"));
1324 return;
1325 }
1326
1327 do
1328 {
1329 //dprintf(("VBoxGuest: performing idle request..\n"));
1330 /* perform idle request */
1331 VbglGRPerform(&req->header);
1332
1333 } while (!pDevExt->stopThread);
1334
1335 VbglGRFree(&req->header);
1336
1337 dprintf(("VBoxGuest::vboxIdleThread leaving\n"));
1338}
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