VirtualBox

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

Last change on this file since 41647 was 41647, checked in by vboxsync, 12 years ago

VBoxGuest: Build fix.

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