VirtualBox

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

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

hrmpf.

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