VirtualBox

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

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

VBoxGuest/win: enable IoDisconnectInterrupt for NT4 also

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