VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp@ 37226

Last change on this file since 37226 was 37226, checked in by vboxsync, 13 years ago

VBoxMouse/VBoxGuest/win: avoid poller thread for mouse events notifications over NEW_PROTOCOL

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.0 KB
Line 
1/** @file
2 *
3 * VBoxGuest - Windows specifics.
4 *
5 * Copyright (C) 2010 Oracle Corporation
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 (GPL) as published by the Free Software
11 * Foundation, in version 2 as it comes in the "COPYING" file of the
12 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
14 */
15
16/*******************************************************************************
17* Header Files *
18*******************************************************************************/
19#define LOG_GROUP LOG_GROUP_SUP_DRV
20#include "VBoxGuest-win.h"
21#include "VBoxGuestInternal.h"
22
23#include <iprt/asm.h>
24
25#include <VBox/log.h>
26#include <VBox/VBoxGuestLib.h>
27
28#include <VBoxGuestInternal.h>
29
30#ifdef TARGET_NT4
31/*
32 * XP DDK #defines ExFreePool to ExFreePoolWithTag. The latter does not exist
33 * on NT4, so... The same for ExAllocatePool.
34 */
35#undef ExAllocatePool
36#undef ExFreePool
37#endif
38
39/*******************************************************************************
40* Defined Constants And Macros *
41*******************************************************************************/
42
43
44/*******************************************************************************
45* Entry Points *
46*******************************************************************************/
47RT_C_DECLS_BEGIN
48static NTSTATUS vboxguestwinAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj);
49static void vboxguestwinUnload(PDRIVER_OBJECT pDrvObj);
50static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
51static NTSTATUS vboxguestwinClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
52static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
53static NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
54static NTSTATUS vboxguestwinSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
55static NTSTATUS vboxguestwinShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp);
56static NTSTATUS vboxguestwinNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
57RT_C_DECLS_END
58
59
60/*******************************************************************************
61* Internal Functions *
62*******************************************************************************/
63RT_C_DECLS_BEGIN
64#ifdef DEBUG
65 static void vboxguestwinDoTests(void);
66#endif
67RT_C_DECLS_END
68
69
70/*******************************************************************************
71* Exported Functions *
72*******************************************************************************/
73RT_C_DECLS_BEGIN
74ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
75RT_C_DECLS_END
76
77#ifdef ALLOC_PRAGMA
78#pragma alloc_text (INIT, DriverEntry)
79#pragma alloc_text (PAGE, vboxguestwinAddDevice)
80#pragma alloc_text (PAGE, vboxguestwinUnload)
81#pragma alloc_text (PAGE, vboxguestwinCreate)
82#pragma alloc_text (PAGE, vboxguestwinClose)
83#pragma alloc_text (PAGE, vboxguestwinIOCtl)
84#pragma alloc_text (PAGE, vboxguestwinShutdown)
85#pragma alloc_text (PAGE, vboxguestwinNotSupportedStub)
86#pragma alloc_text (PAGE, vboxguestwinScanPCIResourceList)
87#endif
88
89/** The detected Windows version. */
90winVersion_t g_winVersion;
91
92/**
93 * Driver entry point.
94 *
95 * @returns appropriate status code.
96 * @param pDrvObj Pointer to driver object.
97 * @param pRegPath Registry base path.
98 */
99ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
100{
101 NTSTATUS rc = STATUS_SUCCESS;
102
103 Log(("VBoxGuest::DriverEntry. Driver built: %s %s\n", __DATE__, __TIME__));
104
105 ULONG majorVersion;
106 ULONG minorVersion;
107 ULONG buildNumber;
108 BOOLEAN bCheckedBuild = PsGetVersion(&majorVersion, &minorVersion, &buildNumber, NULL);
109 Log(("VBoxGuest::DriverEntry: Running on Windows NT version %d.%d, build %d\n", majorVersion, minorVersion, buildNumber));
110 if (bCheckedBuild)
111 Log(("VBoxGuest::DriverEntry: Running on a Windows checked build (debug)!\n"));
112#ifdef DEBUG
113 vboxguestwinDoTests();
114#endif
115 switch (majorVersion)
116 {
117 case 6: /* Windows Vista or Windows 7 (based on minor ver) */
118 switch (minorVersion)
119 {
120 case 0: /* Note: Also could be Windows 2008 Server! */
121 g_winVersion = WINVISTA;
122 break;
123 case 1: /* Note: Also could be Windows 2008 Server R2! */
124 g_winVersion = WIN7;
125 break;
126 default:
127 Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n",
128 majorVersion, minorVersion));
129 rc = STATUS_DRIVER_UNABLE_TO_LOAD;
130 break;
131 }
132 break;
133 case 5:
134 switch (minorVersion)
135 {
136 case 2:
137 g_winVersion = WIN2K3;
138 break;
139 case 1:
140 g_winVersion = WINXP;
141 break;
142 case 0:
143 g_winVersion = WIN2K;
144 break;
145 default:
146 Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n",
147 majorVersion, minorVersion));
148 rc = STATUS_DRIVER_UNABLE_TO_LOAD;
149 }
150 break;
151 case 4:
152 g_winVersion = WINNT4;
153 break;
154 default:
155 Log(("VBoxGuest::DriverEntry: At least Windows NT4 required!\n"));
156 rc = STATUS_DRIVER_UNABLE_TO_LOAD;
157 }
158
159 if (NT_SUCCESS(rc))
160 {
161 /*
162 * Setup the driver entry points in pDrvObj.
163 */
164 pDrvObj->DriverUnload = vboxguestwinUnload;
165 pDrvObj->MajorFunction[IRP_MJ_CREATE] = vboxguestwinCreate;
166 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = vboxguestwinClose;
167 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vboxguestwinIOCtl;
168 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = vboxguestwinInternalIOCtl;
169 pDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = vboxguestwinShutdown;
170 pDrvObj->MajorFunction[IRP_MJ_READ] = vboxguestwinNotSupportedStub;
171 pDrvObj->MajorFunction[IRP_MJ_WRITE] = vboxguestwinNotSupportedStub;
172#ifdef TARGET_NT4
173 rc = vboxguestwinnt4CreateDevice(pDrvObj, NULL /* pDevObj */, pRegPath);
174#else
175 pDrvObj->MajorFunction[IRP_MJ_PNP] = vboxguestwinPnP;
176 pDrvObj->MajorFunction[IRP_MJ_POWER] = vboxguestwinPower;
177 pDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = vboxguestwinSystemControl;
178 pDrvObj->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)vboxguestwinAddDevice;
179#endif
180 }
181
182 Log(("VBoxGuest::DriverEntry returning %#x\n", rc));
183 return rc;
184}
185
186
187#ifndef TARGET_NT4
188/**
189 * Handle request from the Plug & Play subsystem.
190 *
191 * @returns NT status code
192 * @param pDrvObj Driver object
193 * @param pDevObj Device object
194 */
195static NTSTATUS vboxguestwinAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
196{
197 NTSTATUS rc;
198 Log(("VBoxGuest::vboxguestwinGuestAddDevice\n"));
199
200 /*
201 * Create device.
202 */
203 PDEVICE_OBJECT pDeviceObject = NULL;
204 PVBOXGUESTDEVEXT pDevExt = NULL;
205 UNICODE_STRING devName;
206 UNICODE_STRING win32Name;
207 RtlInitUnicodeString(&devName, VBOXGUEST_DEVICE_NAME_NT);
208 rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXT), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
209 if (NT_SUCCESS(rc))
210 {
211 /*
212 * Create symbolic link (DOS devices).
213 */
214 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
215 rc = IoCreateSymbolicLink(&win32Name, &devName);
216 if (NT_SUCCESS(rc))
217 {
218 /*
219 * Setup the device extension.
220 */
221 pDevExt = (PVBOXGUESTDEVEXT)pDeviceObject->DeviceExtension;
222 RtlZeroMemory(pDevExt, sizeof(VBOXGUESTDEVEXT));
223
224 KeInitializeSpinLock(&pDevExt->win.s.MouseEventAccessLock);
225
226 pDevExt->win.s.pDeviceObject = pDeviceObject;
227 pDevExt->win.s.prevDevState = STOPPED;
228 pDevExt->win.s.devState = STOPPED;
229
230 pDevExt->win.s.pNextLowerDriver = IoAttachDeviceToDeviceStack(pDeviceObject, pDevObj);
231 if (pDevExt->win.s.pNextLowerDriver == NULL)
232 {
233 Log(("VBoxGuest::vboxguestwinGuestAddDevice: IoAttachDeviceToDeviceStack did not give a nextLowerDriver!\n"));
234 rc = STATUS_DEVICE_NOT_CONNECTED;
235 }
236 }
237 else
238 Log(("VBoxGuest::vboxguestwinGuestAddDevice: IoCreateSymbolicLink failed with rc=%#x!\n", rc));
239 }
240 else
241 Log(("VBoxGuest::vboxguestwinGuestAddDevice: IoCreateDevice failed with rc=%#x!\n", rc));
242
243 if (NT_SUCCESS(rc))
244 {
245 /*
246 * If we reached this point we're fine with the basic driver setup,
247 * so continue to init our own things.
248 */
249#ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
250 vboxguestwinBugCheckCallback(pDevExt); /* Ignore failure! */
251#endif
252 /* VBoxGuestPower is pageable; ensure we are not called at elevated IRQL */
253 pDeviceObject->Flags |= DO_POWER_PAGABLE;
254
255 /* Driver is ready now. */
256 pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
257 }
258
259 /* Cleanup on error. */
260 if (NT_ERROR(rc))
261 {
262 if (pDevExt)
263 {
264 if (pDevExt->win.s.pNextLowerDriver)
265 IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
266 }
267 IoDeleteSymbolicLink(&win32Name);
268 if (pDeviceObject)
269 IoDeleteDevice(pDeviceObject);
270 }
271
272 Log(("VBoxGuest::vboxguestwinGuestAddDevice: returning with rc = 0x%x\n", rc));
273 return rc;
274}
275#endif
276
277
278/**
279 * Debug helper to dump a device resource list.
280 *
281 * @param pResourceList list of device resources.
282 */
283static void vboxguestwinShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList)
284{
285#ifdef LOG_ENABLED
286 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = pResourceList->PartialDescriptors;
287 ULONG nres = pResourceList->Count;
288 ULONG i;
289
290 for (i = 0; i < nres; ++i, ++resource)
291 {
292 ULONG uType = resource->Type;
293 static char* aszName[] =
294 {
295 "CmResourceTypeNull",
296 "CmResourceTypePort",
297 "CmResourceTypeInterrupt",
298 "CmResourceTypeMemory",
299 "CmResourceTypeDma",
300 "CmResourceTypeDeviceSpecific",
301 "CmResourceTypeBusNumber",
302 "CmResourceTypeDevicePrivate",
303 "CmResourceTypeAssignedResource",
304 "CmResourceTypeSubAllocateFrom",
305 };
306
307 Log(("VBoxGuest::vboxguestwinShowDeviceResources: Type %s",
308 uType < (sizeof(aszName) / sizeof(aszName[0]))
309 ? aszName[uType] : "Unknown"));
310
311 switch (uType)
312 {
313 case CmResourceTypePort:
314 case CmResourceTypeMemory:
315 Log(("VBoxGuest::vboxguestwinShowDeviceResources: Start %8X%8.8lX length %X\n",
316 resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
317 resource->u.Port.Length));
318 break;
319
320 case CmResourceTypeInterrupt:
321 Log(("VBoxGuest::vboxguestwinShowDeviceResources: Level %X, Vector %X, Affinity %X\n",
322 resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
323 resource->u.Interrupt.Affinity));
324 break;
325
326 case CmResourceTypeDma:
327 Log(("VBoxGuest::vboxguestwinShowDeviceResources: Channel %d, Port %X\n",
328 resource->u.Dma.Channel, resource->u.Dma.Port));
329 break;
330
331 default:
332 Log(("\n"));
333 break;
334 }
335 }
336#endif
337}
338
339
340/**
341 * Global initialisation stuff (PnP + NT4 legacy).
342 *
343 * @param pDevObj Device object.
344 * @param pIrp Request packet.
345 */
346#ifndef TARGET_NT4
347NTSTATUS vboxguestwinInit(PDEVICE_OBJECT pDevObj, PIRP pIrp)
348#else
349NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath)
350#endif
351{
352 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
353#ifndef TARGET_NT4
354 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
355#endif
356
357 Log(("VBoxGuest::vboxguestwinInit\n"));
358
359 int rc = STATUS_SUCCESS;
360#ifdef TARGET_NT4
361 /*
362 * Let's have a look at what our PCI adapter offers.
363 */
364 Log(("VBoxGuest::vboxguestwinInit: Starting to scan PCI resources of VBoxGuest ...\n"));
365
366 /* Assign the PCI resources. */
367 PCM_RESOURCE_LIST pResourceList = NULL;
368 UNICODE_STRING classNameString;
369 RtlInitUnicodeString(&classNameString, L"VBoxGuestAdapter");
370 rc = HalAssignSlotResources(pRegPath, &classNameString,
371 pDrvObj, pDevObj,
372 PCIBus, pDevExt->win.s.busNumber, pDevExt->win.s.slotNumber,
373 &pResourceList);
374 if (pResourceList && pResourceList->Count > 0)
375 vboxguestwinShowDeviceResources(&pResourceList->List[0].PartialResourceList);
376 if (NT_SUCCESS(rc))
377 rc = vboxguestwinScanPCIResourceList(pResourceList, pDevExt);
378#else
379 if (pStack->Parameters.StartDevice.AllocatedResources->Count > 0)
380 vboxguestwinShowDeviceResources(&pStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList);
381 if (NT_SUCCESS(rc))
382 rc = vboxguestwinScanPCIResourceList(pStack->Parameters.StartDevice.AllocatedResourcesTranslated,
383 pDevExt);
384#endif
385 if (NT_SUCCESS(rc))
386 {
387 /*
388 * Map physical address of VMMDev memory into MMIO region
389 * and init the common device extension bits.
390 */
391 void *pvMMIOBase = NULL;
392 uint32_t cbMMIO = 0;
393 rc = vboxguestwinMapVMMDevMemory(pDevExt,
394 pDevExt->win.s.vmmDevPhysMemoryAddress,
395 pDevExt->win.s.vmmDevPhysMemoryLength,
396 &pvMMIOBase,
397 &cbMMIO);
398 if (NT_SUCCESS(rc))
399 {
400 pDevExt->pVMMDevMemory = (VMMDevMemory *)pvMMIOBase;
401
402 Log(("VBoxGuest::vboxguestwinInit: pvMMIOBase = 0x%p, pDevExt = 0x%p, pDevExt->pVMMDevMemory = 0x%p\n",
403 pvMMIOBase, pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL));
404
405 int vrc = VBoxGuestInitDevExt(pDevExt,
406 pDevExt->IOPortBase,
407 pvMMIOBase, cbMMIO,
408 vboxguestwinVersionToOSType(g_winVersion),
409 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
410 if (RT_FAILURE(vrc))
411 {
412 Log(("VBoxGuest::vboxguestwinInit: Could not init device extension, rc = %Rrc!\n", vrc));
413 rc = STATUS_DEVICE_CONFIGURATION_ERROR;
414 }
415 }
416 else
417 Log(("VBoxGuest::vboxguestwinInit: Could not map physical address of VMMDev, rc = 0x%x!\n", rc));
418 }
419
420 if (NT_SUCCESS(rc))
421 {
422 int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pDevExt->win.s.pPowerStateRequest,
423 sizeof (VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
424 if (RT_FAILURE(vrc))
425 {
426 Log(("VBoxGuest::vboxguestwinInit: Alloc for pPowerStateRequest failed, rc = %Rrc\n", vrc));
427 rc = STATUS_UNSUCCESSFUL;
428 }
429 }
430
431 if (NT_SUCCESS(rc))
432 {
433 /*
434 * Register DPC and ISR.
435 */
436 Log(("VBoxGuest::vboxguestwinInit: Initializing DPC/ISR ...\n"));
437
438 IoInitializeDpcRequest(pDevExt->win.s.pDeviceObject, vboxguestwinDpcHandler);
439#ifdef TARGET_NT4
440 ULONG uInterruptVector;
441 KIRQL irqLevel;
442 /* Get an interrupt vector. */
443 /* Only proceed if the device provides an interrupt. */
444 if ( pDevExt->win.s.interruptLevel
445 || pDevExt->win.s.interruptVector)
446 {
447 Log(("VBoxGuest::vboxguestwinInit: Getting interrupt vector (HAL): Bus: %u, IRQL: %u, Vector: %u\n",
448 pDevExt->win.s.busNumber, pDevExt->win.s.interruptLevel, pDevExt->win.s.interruptVector));
449
450 uInterruptVector = HalGetInterruptVector(PCIBus,
451 pDevExt->win.s.busNumber,
452 pDevExt->win.s.interruptLevel,
453 pDevExt->win.s.interruptVector,
454 &irqLevel,
455 &pDevExt->win.s.interruptAffinity);
456 Log(("VBoxGuest::vboxguestwinInit: HalGetInterruptVector returns vector %u\n", uInterruptVector));
457 if (uInterruptVector == 0)
458 Log(("VBoxGuest::vboxguestwinInit: No interrupt vector found!\n"));
459 }
460 else
461 Log(("VBoxGuest::vboxguestwinInit: Device does not provide an interrupt!\n"));
462#endif
463 if (pDevExt->win.s.interruptVector)
464 {
465 Log(("VBoxGuest::vboxguestwinInit: Connecting interrupt ...\n"));
466
467 rc = IoConnectInterrupt(&pDevExt->win.s.pInterruptObject, /* Out: interrupt object. */
468 (PKSERVICE_ROUTINE)vboxguestwinIsrHandler, /* Our ISR handler. */
469 pDevExt, /* Device context. */
470 NULL, /* Optional spinlock. */
471#ifdef TARGET_NT4
472 uInterruptVector, /* Interrupt vector. */
473 irqLevel, /* Interrupt level. */
474 irqLevel, /* Interrupt level. */
475#else
476 pDevExt->win.s.interruptVector, /* Interrupt vector. */
477 (KIRQL)pDevExt->win.s.interruptLevel, /* Interrupt level. */
478 (KIRQL)pDevExt->win.s.interruptLevel, /* Interrupt level. */
479#endif
480 pDevExt->win.s.interruptMode, /* LevelSensitive or Latched. */
481 TRUE, /* Shareable interrupt. */
482 pDevExt->win.s.interruptAffinity, /* CPU affinity. */
483 FALSE); /* Don't save FPU stack. */
484 if (NT_ERROR(rc))
485 Log(("VBoxGuest::vboxguestwinInit: Could not connect interrupt, rc = 0x%x\n", rc));
486 }
487 else
488 Log(("VBoxGuest::vboxguestwinInit: No interrupt vector found!\n"));
489 }
490
491
492#ifdef VBOX_WITH_HGCM
493 Log(("VBoxGuest::vboxguestwinInit: Allocating kernel session data ...\n"));
494 int vrc = VBoxGuestCreateKernelSession(pDevExt, &pDevExt->win.s.pKernelSession);
495 if (RT_FAILURE(vrc))
496 {
497 Log(("VBoxGuest::vboxguestwinInit: Failed to allocated kernel session data! rc = %Rrc\n", rc));
498 rc = STATUS_UNSUCCESSFUL;
499 }
500#endif
501
502 if (RT_SUCCESS(rc))
503 {
504 /* Ready to rumble! */
505 Log(("VBoxGuest::vboxguestwinInit: Device is ready!\n"));
506 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, WORKING);
507 }
508 else
509 {
510 pDevExt->win.s.pInterruptObject = NULL;
511 }
512
513 Log(("VBoxGuest::vboxguestwinInit: Returned with rc = 0x%x\n", rc));
514 return rc;
515}
516
517
518/**
519 * Cleans up hardware resources.
520 * Do not delete DevExt here.
521 *
522 * @param pDrvObj Driver object.
523 */
524NTSTATUS vboxguestwinCleanup(PDEVICE_OBJECT pDevObj)
525{
526 Log(("VBoxGuest::vboxguestwinCleanup\n"));
527
528 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
529 if (pDevExt)
530 {
531#ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
532 hlpDeregisterBugCheckCallback(pDevExt); /* ignore failure! */
533#endif
534 /* According to MSDN we have to unmap previously mapped memory. */
535 vboxguestwinUnmapVMMDevMemory(pDevExt);
536 }
537 return STATUS_SUCCESS;
538}
539
540
541/**
542 * Unload the driver.
543 *
544 * @param pDrvObj Driver object.
545 */
546void vboxguestwinUnload(PDRIVER_OBJECT pDrvObj)
547{
548 Log(("VBoxGuest::vboxguestwinGuestUnload\n"));
549#ifdef TARGET_NT4
550 vboxguestwinCleanup(pDrvObj->DeviceObject);
551
552 /* Destroy device extension and clean up everything else. */
553 if (pDrvObj->DeviceObject && pDrvObj->DeviceObject->DeviceExtension)
554 VBoxGuestDeleteDevExt((PVBOXGUESTDEVEXT)pDrvObj->DeviceObject->DeviceExtension);
555
556 /*
557 * I don't think it's possible to unload a driver which processes have
558 * opened, at least we'll blindly assume that here.
559 */
560 UNICODE_STRING win32Name;
561 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
562 NTSTATUS rc = IoDeleteSymbolicLink(&win32Name);
563
564 IoDeleteDevice(pDrvObj->DeviceObject);
565#else /* TARGET_NT4 */
566 /* On a PnP driver this routine will be called after
567 * IRP_MN_REMOVE_DEVICE (where we already did the cleanup),
568 * so don't do anything here (yet). */
569#endif
570
571 Log(("VBoxGuest::vboxguestwinGuestUnload: returning\n"));
572}
573
574
575/**
576 * Create (i.e. Open) file entry point.
577 *
578 * @param pDevObj Device object.
579 * @param pIrp Request packet.
580 */
581NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
582{
583 /** @todo AssertPtrReturn(pIrp); */
584 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
585 /** @todo AssertPtrReturn(pStack); */
586 PFILE_OBJECT pFileObj = pStack->FileObject;
587 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
588 NTSTATUS rc = STATUS_SUCCESS;
589
590 if (pDevExt->win.s.devState != WORKING)
591 {
592 Log(("VBoxGuest::vboxguestwinGuestCreate: device is not working currently: %d!\n",
593 pDevExt->win.s.devState));
594 rc = STATUS_UNSUCCESSFUL;
595 }
596 else if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
597 {
598 /*
599 * We are not remotely similar to a directory...
600 * (But this is possible.)
601 */
602 Log(("VBoxGuest::vboxguestwinGuestCreate: Uhm, we're not a directory!\n"));
603 rc = STATUS_NOT_A_DIRECTORY;
604 }
605 else
606 {
607#ifdef VBOX_WITH_HGCM
608 if (pFileObj)
609 {
610 Log(("VBoxGuest::vboxguestwinGuestCreate: File object type = %d\n",
611 pFileObj->Type));
612
613 int vrc;
614 PVBOXGUESTSESSION pSession;
615 if (pFileObj->Type == 5 /* File Object */)
616 {
617 /*
618 * Create a session object if we have a valid file object. This session object
619 * exists for every R3 process.
620 */
621 vrc = VBoxGuestCreateUserSession(pDevExt, &pSession);
622 }
623 else
624 {
625 /* ... otherwise we've been called from R0! */
626 vrc = VBoxGuestCreateKernelSession(pDevExt, &pSession);
627 }
628 if (RT_SUCCESS(vrc))
629 pFileObj->FsContext = pSession;
630 }
631#endif
632 }
633
634 /* Complete the request! */
635 pIrp->IoStatus.Information = 0;
636 pIrp->IoStatus.Status = rc;
637 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
638
639 Log(("VBoxGuest::vboxguestwinGuestCreate: Returning 0x%x\n", rc));
640 return rc;
641}
642
643
644/**
645 * Close file entry point.
646 *
647 * @param pDevObj Device object.
648 * @param pIrp Request packet.
649 */
650NTSTATUS vboxguestwinClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
651{
652 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
653 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
654 PFILE_OBJECT pFileObj = pStack->FileObject;
655
656 Log(("VBoxGuest::vboxguestwinGuestClose: pDevExt=0x%p pFileObj=0x%p FsContext=0x%p\n",
657 pDevExt, pFileObj, pFileObj->FsContext));
658
659#ifdef VBOX_WITH_HGCM
660 /* Close both, R0 and R3 sessions. */
661 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFileObj->FsContext;
662 if (pSession)
663 VBoxGuestCloseSession(pDevExt, pSession);
664#endif
665
666 pFileObj->FsContext = NULL;
667 pIrp->IoStatus.Information = 0;
668 pIrp->IoStatus.Status = STATUS_SUCCESS;
669 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
670
671 return STATUS_SUCCESS;
672}
673
674
675/**
676 * Device I/O Control entry point.
677 *
678 * @param pDevObj Device object.
679 * @param pIrp Request packet.
680 */
681NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
682{
683 NTSTATUS Status = STATUS_SUCCESS;
684 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
685 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
686 unsigned int uCmd = (unsigned int)pStack->Parameters.DeviceIoControl.IoControlCode;
687
688 char *pBuf = (char *)pIrp->AssociatedIrp.SystemBuffer; /* All requests are buffered. */
689 size_t cbData = pStack->Parameters.DeviceIoControl.InputBufferLength;
690 unsigned cbOut = 0;
691
692 /* Do we have a file object associated?*/
693 PFILE_OBJECT pFileObj = pStack->FileObject;
694 PVBOXGUESTSESSION pSession = NULL;
695 if (pFileObj) /* ... then we might have a session object as well! */
696 pSession = (PVBOXGUESTSESSION)pFileObj->FsContext;
697
698 Log(("VBoxGuest::vboxguestwinIOCtl: uCmd=%u, pDevExt=0x%p, pSession=0x%p\n",
699 uCmd, pDevExt, pSession));
700
701 /* We don't have a session associated with the file object? So this seems
702 * to be a kernel call then. */
703 if (pSession == NULL)
704 {
705 Log(("VBoxGuest::vboxguestwinIOCtl: Using kernel session data ...\n"));
706 pSession = pDevExt->win.s.pKernelSession;
707 }
708
709 /*
710 * First process Windows specific stuff which cannot be handled
711 * by the common code used on all other platforms. In the default case
712 * we then finally handle the common cases.
713 */
714 switch (uCmd)
715 {
716#ifdef VBOX_WITH_VRDP_SESSION_HANDLING
717 case VBOXGUEST_IOCTL_ENABLE_VRDP_SESSION:
718 {
719 LogRel(("VBoxGuest::vboxguestwinIOCtl: ENABLE_VRDP_SESSION: Currently: %sabled\n",
720 pDevExt->fVRDPEnabled? "en": "dis"));
721 if (!pDevExt->fVRDPEnabled)
722 {
723 KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
724
725 pDevExt->fVRDPEnabled = TRUE;
726 LogRel(("VBoxGuest::vboxguestwinIOCtl: ENABLE_VRDP_SESSION: Current active console ID: 0x%08X\n",
727 pSharedUserData->ActiveConsoleId));
728 pDevExt->ulOldActiveConsoleId = pSharedUserData->ActiveConsoleId;
729 pSharedUserData->ActiveConsoleId = 2;
730 }
731 break;
732 }
733
734 case VBOXGUEST_IOCTL_DISABLE_VRDP_SESSION:
735 {
736 LogRel(("VBoxGuest::vboxguestwinIOCtl: DISABLE_VRDP_SESSION: Currently: %sabled\n",
737 pDevExt->fVRDPEnabled? "en": "dis"));
738 if (pDevExt->fVRDPEnabled)
739 {
740 KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
741
742 pDevExt->fVRDPEnabled = FALSE;
743 Log(("VBoxGuest::vboxguestwinIOCtl: DISABLE_VRDP_SESSION: Current active console ID: 0x%08X\n",
744 pSharedUserData->ActiveConsoleId));
745 pSharedUserData->ActiveConsoleId = pDevExt->ulOldActiveConsoleId;
746 pDevExt->ulOldActiveConsoleId = 0;
747 }
748 break;
749 }
750#else
751 /* Add at least one (bogus) fall through case to shut up MSVC! */
752 case 0:
753#endif
754 default:
755 {
756 /*
757 * Process the common IOCtls.
758 */
759 size_t cbDataReturned;
760 int vrc = VBoxGuestCommonIOCtl(uCmd, pDevExt, pSession, (void*)pBuf, cbData, &cbDataReturned);
761
762 Log(("VBoxGuest::vboxguestwinGuestDeviceControl: rc=%Rrc, pBuf=0x%p, cbData=%u, cbDataReturned=%u\n",
763 vrc, pBuf, cbData, cbDataReturned));
764
765 if (RT_SUCCESS(vrc))
766 {
767 if (RT_UNLIKELY(cbDataReturned > cbData))
768 {
769 Log(("VBoxGuest::vboxguestwinGuestDeviceControl: Too much output data %u - expected %u!\n", cbDataReturned, cbData));
770 cbDataReturned = cbData;
771 Status = STATUS_BUFFER_TOO_SMALL;
772 }
773 if (cbDataReturned > 0)
774 cbOut = cbDataReturned;
775 }
776 else
777 {
778 if ( vrc == VERR_NOT_SUPPORTED
779 || vrc == VERR_INVALID_PARAMETER)
780 {
781 Status = STATUS_INVALID_PARAMETER;
782 }
783 else
784 Status = STATUS_UNSUCCESSFUL;
785 }
786 break;
787 }
788 }
789
790 pIrp->IoStatus.Status = Status;
791 pIrp->IoStatus.Information = cbOut;
792
793 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
794
795 //Log(("VBoxGuest::vboxguestwinGuestDeviceControl: returned cbOut=%d rc=%#x\n", cbOut, Status));
796 return Status;
797}
798
799/* we do not want to allow some IOCTLs to be originated from user mode,
800 * this is why we have a separate vboxguestwinInternalIOCtl for internal IOCTLs */
801NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
802{
803 NTSTATUS Status = STATUS_SUCCESS;
804 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
805 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
806 unsigned int uCmd = (unsigned int)pStack->Parameters.DeviceIoControl.IoControlCode;
807 BOOLEAN fProcessed = FALSE;
808 unsigned Info = 0;
809
810 switch (uCmd)
811 {
812 case VBOXGUEST_IOCTL_INTERNAL_SET_MOUSE_NOTIFY_CALLBACK:
813 {
814 PVOID pvBuf = pStack->Parameters.Others.Argument1;
815 size_t cbData = (size_t)pStack->Parameters.Others.Argument2;
816 fProcessed = true;
817 if (cbData != sizeof(VBoxGuestMouseSetNotifyCallback))
818 {
819 AssertFailed();
820 Status = STATUS_INVALID_PARAMETER;
821 break;
822 }
823
824 KIRQL OldIrql;
825 VBoxGuestMouseSetNotifyCallback *pInfo = (VBoxGuestMouseSetNotifyCallback*)pvBuf;
826 /* we need a lock here to avoid concurrency with the set event functionality */
827 KeAcquireSpinLock(&pDevExt->win.s.MouseEventAccessLock, &OldIrql);
828 pDevExt->win.s.pfnMouseNotify = pInfo->pfnNotify;
829 pDevExt->win.s.pvMouseNotify = pInfo->pvNotify;
830 KeReleaseSpinLock(&pDevExt->win.s.MouseEventAccessLock, OldIrql);
831
832 Status = STATUS_SUCCESS;
833 break;
834 }
835
836 default:
837 break;
838 }
839
840
841 if (fProcessed)
842 {
843 pIrp->IoStatus.Status = Status;
844 pIrp->IoStatus.Information = Info;
845
846 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
847 return Status;
848 }
849
850 return vboxguestwinIOCtl(pDevObj, pIrp);
851}
852
853
854/**
855 * IRP_MJ_SYSTEM_CONTROL handler.
856 *
857 * @returns NT status code
858 * @param pDevObj Device object.
859 * @param pIrp IRP.
860 */
861NTSTATUS vboxguestwinSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
862{
863 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
864
865 Log(("VBoxGuest::vboxguestwinGuestSystemControl\n"));
866
867 /* Always pass it on to the next driver. */
868 IoSkipCurrentIrpStackLocation(pIrp);
869
870 return IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
871}
872
873
874/**
875 * IRP_MJ_SHUTDOWN handler.
876 *
877 * @returns NT status code
878 * @param pDevObj Device object.
879 * @param pIrp IRP.
880 */
881NTSTATUS vboxguestwinShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
882{
883 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
884
885 Log(("VBoxGuest::vboxguestwinGuestShutdown\n"));
886
887 VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
888 if (pReq)
889 {
890 pReq->header.requestType = VMMDevReq_SetPowerStatus;
891 pReq->powerState = VMMDevPowerState_PowerOff;
892
893 int rc = VbglGRPerform(&pReq->header);
894 if (RT_FAILURE(rc))
895 {
896 Log(("VBoxGuest::vboxguestwinGuestShutdown: Error performing request to VMMDev! "
897 "rc = %Rrc\n", rc));
898 }
899 }
900 return STATUS_SUCCESS;
901}
902
903
904/**
905 * Stub function for functions we don't implemented.
906 *
907 * @returns STATUS_NOT_SUPPORTED
908 * @param pDevObj Device object.
909 * @param pIrp IRP.
910 */
911NTSTATUS vboxguestwinNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
912{
913 Log(("VBoxGuest::vboxguestwinGuestNotSupportedStub\n"));
914
915 pIrp->IoStatus.Information = 0;
916 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
917 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
918
919 return STATUS_NOT_SUPPORTED;
920}
921
922
923/**
924 * DPC handler.
925 *
926 * @param pDPC DPC descriptor.
927 * @param pDevObj Device object.
928 * @param pIrp Interrupt request packet.
929 * @param pContext Context specific pointer.
930 */
931void vboxguestwinDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj,
932 PIRP pIrp, PVOID pContext)
933{
934 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
935 Log(("VBoxGuest::vboxguestwinGuestDpcHandler: pDevExt=0x%p\n", pDevExt));
936
937 /* test & reset the counter */
938 if (ASMAtomicXchgU32(&pDevExt->u32MousePosChangedSeq, 0))
939 {
940 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
941 /* we need a lock here to avoid concurrency with the set event ioctl handler thread,
942 * i.e. to prevent the event from destroyed while we're using it */
943 KeAcquireSpinLockAtDpcLevel(&pDevExt->win.s.MouseEventAccessLock);
944 if (pDevExt->win.s.pfnMouseNotify)
945 {
946 pDevExt->win.s.pfnMouseNotify(pDevExt->win.s.pvMouseNotify);
947 }
948 KeReleaseSpinLockFromDpcLevel(&pDevExt->win.s.MouseEventAccessLock);
949 }
950
951 /* Process the wake-up list we were asked by the scheduling a DPC
952 * in vboxguestwinIsrHandler(). */
953 VBoxGuestWaitDoWakeUps(pDevExt);
954}
955
956
957/**
958 * ISR handler.
959 *
960 * @return BOOLEAN Indicates whether the IRQ came from us (TRUE) or not (FALSE).
961 * @param pInterrupt Interrupt that was triggered.
962 * @param pServiceContext Context specific pointer.
963 */
964BOOLEAN vboxguestwinIsrHandler(PKINTERRUPT pInterrupt, PVOID pServiceContext)
965{
966 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pServiceContext;
967 if (pDevExt == NULL)
968 return FALSE;
969
970 /*Log(("VBoxGuest::vboxguestwinGuestIsrHandler: pDevExt = 0x%p, pVMMDevMemory = 0x%p\n",
971 pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL));*/
972
973 /* Enter the common ISR routine and do the actual work. */
974 BOOLEAN fIRQTaken = VBoxGuestCommonISR(pDevExt);
975
976 /* If we need to wake up some events we do that in a DPC to make
977 * sure we're called at the right IRQL. */
978 if (fIRQTaken)
979 {
980 Log(("VBoxGuest::vboxguestwinGuestIsrHandler: IRQ was taken! pInterrupt = 0x%p, pDevExt = 0x%p\n",
981 pInterrupt, pDevExt));
982 if (ASMAtomicUoReadU32(&pDevExt->u32MousePosChangedSeq) || !RTListIsEmpty(&pDevExt->WakeUpList))
983 {
984 Log(("VBoxGuest::vboxguestwinGuestIsrHandler: Requesting DPC ...\n"));
985 IoRequestDpc(pDevExt->win.s.pDeviceObject, pDevExt->win.s.pCurrentIrp, NULL);
986 }
987 }
988 return fIRQTaken;
989}
990
991
992/*
993 * Overridden routine for mouse polling events.
994 *
995 * @param pDevExt Device extension structure.
996 */
997void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
998{
999 NOREF(pDevExt);
1000 /* nothing to do here - i.e. since we can not KeSetEvent from ISR level,
1001 * we rely on the pDevExt->u32MousePosChangedSeq to be set to a non-zero value on a mouse event
1002 * and queue the DPC in our ISR routine in that case doing KeSetEvent from the DPC routine */
1003}
1004
1005
1006/**
1007 * Helper to scan the PCI resource list and remember stuff.
1008 *
1009 * @param pResList Resource list
1010 * @param pDevExt Device extension
1011 */
1012NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTDEVEXT pDevExt)
1013{
1014 /* Enumerate the resource list. */
1015 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Found %d resources\n",
1016 pResList->List->PartialResourceList.Count));
1017
1018 NTSTATUS rc = STATUS_SUCCESS;
1019 PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialData = NULL;
1020 ULONG rangeCount = 0;
1021 ULONG cMMIORange = 0;
1022 PVBOXGUESTWINBASEADDRESS pBaseAddress = pDevExt->win.s.pciBaseAddress;
1023 for (ULONG i = 0; i < pResList->List->PartialResourceList.Count; i++)
1024 {
1025 pPartialData = &pResList->List->PartialResourceList.PartialDescriptors[i];
1026 switch (pPartialData->Type)
1027 {
1028 case CmResourceTypePort:
1029 {
1030 /* Overflow protection. */
1031 if (rangeCount < PCI_TYPE0_ADDRESSES)
1032 {
1033 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: I/O range: Base = %08x:%08x, Length = %08x\n",
1034 pPartialData->u.Port.Start.HighPart,
1035 pPartialData->u.Port.Start.LowPart,
1036 pPartialData->u.Port.Length));
1037
1038 /* Save the IO port base. */
1039 /** @todo Not so good. */
1040 pDevExt->IOPortBase = (RTIOPORT)pPartialData->u.Port.Start.LowPart;
1041
1042 /* Save resource information. */
1043 pBaseAddress->RangeStart = pPartialData->u.Port.Start;
1044 pBaseAddress->RangeLength = pPartialData->u.Port.Length;
1045 pBaseAddress->RangeInMemory = FALSE;
1046 pBaseAddress->ResourceMapped = FALSE;
1047
1048 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: I/O range for VMMDev found! Base = %08x:%08x, Length = %08x\n",
1049 pPartialData->u.Port.Start.HighPart,
1050 pPartialData->u.Port.Start.LowPart,
1051 pPartialData->u.Port.Length));
1052
1053 /* Next item ... */
1054 rangeCount++; pBaseAddress++;
1055 }
1056 break;
1057 }
1058
1059 case CmResourceTypeInterrupt:
1060 {
1061 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Interrupt: Level = %x, Vector = %x, Mode = %x\n",
1062 pPartialData->u.Interrupt.Level,
1063 pPartialData->u.Interrupt.Vector,
1064 pPartialData->Flags));
1065
1066 /* Save information. */
1067 pDevExt->win.s.interruptLevel = pPartialData->u.Interrupt.Level;
1068 pDevExt->win.s.interruptVector = pPartialData->u.Interrupt.Vector;
1069 pDevExt->win.s.interruptAffinity = pPartialData->u.Interrupt.Affinity;
1070
1071 /* Check interrupt mode. */
1072 if (pPartialData->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
1073 {
1074 pDevExt->win.s.interruptMode = Latched;
1075 }
1076 else
1077 {
1078 pDevExt->win.s.interruptMode = LevelSensitive;
1079 }
1080 break;
1081 }
1082
1083 case CmResourceTypeMemory:
1084 {
1085 /* Overflow protection. */
1086 if (rangeCount < PCI_TYPE0_ADDRESSES)
1087 {
1088 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Memory range: Base = %08x:%08x, Length = %08x\n",
1089 pPartialData->u.Memory.Start.HighPart,
1090 pPartialData->u.Memory.Start.LowPart,
1091 pPartialData->u.Memory.Length));
1092
1093 /* We only care about read/write memory. */
1094 /** @todo Reconsider memory type. */
1095 if ( cMMIORange == 0 /* Only care about the first MMIO range (!!!). */
1096 && (pPartialData->Flags & VBOX_CM_PRE_VISTA_MASK) == CM_RESOURCE_MEMORY_READ_WRITE)
1097 {
1098 /* Save physical MMIO base + length for VMMDev. */
1099 pDevExt->win.s.vmmDevPhysMemoryAddress = pPartialData->u.Memory.Start;
1100 pDevExt->win.s.vmmDevPhysMemoryLength = (ULONG)pPartialData->u.Memory.Length;
1101
1102 /* Save resource information. */
1103 pBaseAddress->RangeStart = pPartialData->u.Memory.Start;
1104 pBaseAddress->RangeLength = pPartialData->u.Memory.Length;
1105 pBaseAddress->RangeInMemory = TRUE;
1106 pBaseAddress->ResourceMapped = FALSE;
1107
1108 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Memory range for VMMDev found! Base = %08x:%08x, Length = %08x\n",
1109 pPartialData->u.Memory.Start.HighPart,
1110 pPartialData->u.Memory.Start.LowPart,
1111 pPartialData->u.Memory.Length));
1112
1113 /* Next item ... */
1114 rangeCount++; pBaseAddress++; cMMIORange++;
1115 }
1116 else
1117 {
1118 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Ignoring memory: Flags = %08x\n",
1119 pPartialData->Flags));
1120 }
1121 }
1122 break;
1123 }
1124
1125 default:
1126 {
1127 Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Unhandled resource found, type = %d\n", pPartialData->Type));
1128 break;
1129 }
1130 }
1131 }
1132
1133 /* Memorize the number of resources found. */
1134 pDevExt->win.s.pciAddressCount = rangeCount;
1135 return rc;
1136}
1137
1138
1139/**
1140 * Maps the I/O space from VMMDev to virtual kernel address space.
1141 *
1142 * @return NTSTATUS
1143 *
1144 * @param pDevExt The device extension.
1145 * @param physicalAdr Physical address to map.
1146 * @param ulLength Length (in bytes) to map.
1147 * @param ppvMMIOBase Pointer of mapped I/O base.
1148 * @param pcbMMIO Length of mapped I/O base.
1149 */
1150NTSTATUS vboxguestwinMapVMMDevMemory(PVBOXGUESTDEVEXT pDevExt, PHYSICAL_ADDRESS physicalAdr, ULONG ulLength,
1151 void **ppvMMIOBase, uint32_t *pcbMMIO)
1152{
1153 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1154 AssertPtrReturn(ppvMMIOBase, VERR_INVALID_POINTER);
1155 /* pcbMMIO is optional. */
1156
1157 NTSTATUS rc = STATUS_SUCCESS;
1158 if (physicalAdr.LowPart > 0) /* We're mapping below 4GB. */
1159 {
1160 VMMDevMemory *pVMMDevMemory = (VMMDevMemory *)MmMapIoSpace(physicalAdr, ulLength, MmNonCached);
1161 Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: pVMMDevMemory = 0x%x\n", pVMMDevMemory));
1162 if (pVMMDevMemory)
1163 {
1164 Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: VMMDevMemory: Version = 0x%x, Size = %d\n",
1165 pVMMDevMemory->u32Version, pVMMDevMemory->u32Size));
1166
1167 /* Check version of the structure; do we have the right memory version? */
1168 if (pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION)
1169 {
1170 Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: Wrong version (%u), refusing operation!\n",
1171 pVMMDevMemory->u32Version));
1172
1173 /* Not our version, refuse operation and unmap the memory. */
1174 vboxguestwinUnmapVMMDevMemory(pDevExt);
1175 rc = STATUS_UNSUCCESSFUL;
1176 }
1177 else
1178 {
1179 /* Save results. */
1180 *ppvMMIOBase = pVMMDevMemory;
1181 if (pcbMMIO) /* Optional. */
1182 *pcbMMIO = pVMMDevMemory->u32Size;
1183
1184 Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: VMMDevMemory found and mapped! pvMMIOBase = 0x%p\n",
1185 *ppvMMIOBase));
1186 }
1187 }
1188 else
1189 rc = STATUS_UNSUCCESSFUL;
1190 }
1191 return rc;
1192}
1193
1194
1195/**
1196 * Unmaps the VMMDev I/O range from kernel space.
1197 *
1198 * @param pDevExt The device extension.
1199 */
1200void vboxguestwinUnmapVMMDevMemory(PVBOXGUESTDEVEXT pDevExt)
1201{
1202 Log(("VBoxGuest::vboxguestwinUnmapVMMDevMemory: pVMMDevMemory = 0x%x\n", pDevExt->pVMMDevMemory));
1203 if (pDevExt->pVMMDevMemory)
1204 {
1205 MmUnmapIoSpace((void*)pDevExt->pVMMDevMemory, pDevExt->win.s.vmmDevPhysMemoryLength);
1206 pDevExt->pVMMDevMemory = NULL;
1207 }
1208
1209 pDevExt->win.s.vmmDevPhysMemoryAddress.QuadPart = 0;
1210 pDevExt->win.s.vmmDevPhysMemoryLength = 0;
1211}
1212
1213
1214VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
1215{
1216 VBOXOSTYPE enmOsType;
1217 switch (winVer)
1218 {
1219 case WINNT4:
1220 enmOsType = VBOXOSTYPE_WinNT4;
1221 break;
1222
1223 case WIN2K:
1224 enmOsType = VBOXOSTYPE_Win2k;
1225 break;
1226
1227 case WINXP:
1228#if ARCH_BITS == 64
1229 enmOsType = VBOXOSTYPE_WinXP_x64;
1230#else
1231 enmOsType = VBOXOSTYPE_WinXP;
1232#endif
1233 break;
1234
1235 case WIN2K3:
1236#if ARCH_BITS == 64
1237 enmOsType = VBOXOSTYPE_Win2k3_x64;
1238#else
1239 enmOsType = VBOXOSTYPE_Win2k3;
1240#endif
1241 break;
1242
1243 case WINVISTA:
1244#if ARCH_BITS == 64
1245 enmOsType = VBOXOSTYPE_WinVista_x64;
1246#else
1247 enmOsType = VBOXOSTYPE_WinVista;
1248#endif
1249 break;
1250
1251 case WIN7:
1252#if ARCH_BITS == 64
1253 enmOsType = VBOXOSTYPE_Win7_x64;
1254#else
1255 enmOsType = VBOXOSTYPE_Win7;
1256#endif
1257 break;
1258
1259 default:
1260 /* We don't know, therefore NT family. */
1261 enmOsType = VBOXOSTYPE_WinNT;
1262 break;
1263 }
1264 return enmOsType;
1265}
1266
1267
1268#ifdef DEBUG
1269/** A quick implementation of AtomicTestAndClear for uint32_t and multiple
1270 * bits.
1271 */
1272static uint32_t vboxugestwinAtomicBitsTestAndClear(void *pu32Bits, uint32_t u32Mask)
1273{
1274 AssertPtrReturn(pu32Bits, 0);
1275 LogFlowFunc(("*pu32Bits=0x%x, u32Mask=0x%x\n", *(long *)pu32Bits,
1276 u32Mask));
1277 uint32_t u32Result = 0;
1278 uint32_t u32WorkingMask = u32Mask;
1279 int iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
1280
1281 while (iBitOffset > 0)
1282 {
1283 bool fSet = ASMAtomicBitTestAndClear(pu32Bits, iBitOffset - 1);
1284 if (fSet)
1285 u32Result |= 1 << (iBitOffset - 1);
1286 u32WorkingMask &= ~(1 << (iBitOffset - 1));
1287 iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
1288 }
1289 LogFlowFunc(("Returning 0x%x\n", u32Result));
1290 return u32Result;
1291}
1292
1293
1294static void vboxguestwinTestAtomicTestAndClearBitsU32(uint32_t u32Mask, uint32_t u32Bits,
1295 uint32_t u32Exp)
1296{
1297 ULONG u32Bits2 = u32Bits;
1298 uint32_t u32Result = vboxugestwinAtomicBitsTestAndClear(&u32Bits2, u32Mask);
1299 if ( u32Result != u32Exp
1300 || (u32Bits2 & u32Mask)
1301 || (u32Bits2 & u32Result)
1302 || ((u32Bits2 | u32Result) != u32Bits)
1303 )
1304 AssertLogRelMsgFailed(("%s: TEST FAILED: u32Mask=0x%x, u32Bits (before)=0x%x, u32Bits (after)=0x%x, u32Result=0x%x, u32Exp=ox%x\n",
1305 __PRETTY_FUNCTION__, u32Mask, u32Bits, u32Bits2,
1306 u32Result));
1307}
1308
1309
1310static void vboxguestwinDoTests()
1311{
1312 vboxguestwinTestAtomicTestAndClearBitsU32(0x00, 0x23, 0);
1313 vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0, 0);
1314 vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0x22, 0);
1315 vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0x23, 0x1);
1316 vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0x32, 0x10);
1317 vboxguestwinTestAtomicTestAndClearBitsU32(0x22, 0x23, 0x22);
1318}
1319#endif
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