VirtualBox

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

Last change on this file since 70274 was 70274, checked in by vboxsync, 7 years ago

VBoxGuest-win.cpp: Reintroduced the bugcheck callback and backdoor logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 98.2 KB
Line 
1/* $Id: VBoxGuest-win.cpp 70274 2017-12-21 13:39:30Z vboxsync $ */
2/** @file
3 * VBoxGuest - Windows specifics.
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#include <iprt/nt/ntddk.h>
33
34#include "VBoxGuestInternal.h"
35#include <VBox/VBoxGuestLib.h>
36#include <VBox/log.h>
37
38#include <iprt/asm.h>
39#include <iprt/asm-amd64-x86.h>
40#include <iprt/dbg.h>
41#include <iprt/initterm.h>
42#include <iprt/memobj.h>
43#include <iprt/spinlock.h>
44#include <iprt/string.h>
45
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51#undef ExFreePool
52
53#ifndef PCI_MAX_BUSES
54# define PCI_MAX_BUSES 256
55#endif
56
57/** CM_RESOURCE_MEMORY_* flags which were used on XP or earlier. */
58#define VBOX_CM_PRE_VISTA_MASK (0x3f)
59
60
61#define VBOXGUEST_UPDATE_DEVSTATE(a_pDevExt, a_enmNewDevState) \
62 do { \
63 (a_pDevExt)->enmPrevDevState = (a_pDevExt)->enmDevState; \
64 (a_pDevExt)->enmDevState = (a_enmNewDevState); \
65 } while (0)
66
67
68/*********************************************************************************************************************************
69* Structures and Typedefs *
70*********************************************************************************************************************************/
71/**
72 * Possible device states for our state machine.
73 */
74typedef enum VGDRVNTDEVSTATE
75{
76 VGDRVNTDEVSTATE_STOPPED,
77 VGDRVNTDEVSTATE_WORKING,
78 VGDRVNTDEVSTATE_PENDINGSTOP,
79 VGDRVNTDEVSTATE_PENDINGREMOVE,
80 VGDRVNTDEVSTATE_SURPRISEREMOVED,
81 VGDRVNTDEVSTATE_REMOVED
82} VGDRVNTDEVSTATE;
83
84
85typedef struct VBOXGUESTWINBASEADDRESS
86{
87 /** Original device physical address. */
88 PHYSICAL_ADDRESS RangeStart;
89 /** Length of I/O or memory range. */
90 ULONG RangeLength;
91 /** Flag: Unmapped range is I/O or memory range. */
92 BOOLEAN RangeInMemory;
93 /** Mapped I/O or memory range. */
94 PVOID MappedRangeStart;
95 /** Flag: mapped range is I/O or memory range. */
96 BOOLEAN MappedRangeInMemory;
97 /** Flag: resource is mapped (i.e. MmMapIoSpace called). */
98 BOOLEAN ResourceMapped;
99} VBOXGUESTWINBASEADDRESS;
100typedef VBOXGUESTWINBASEADDRESS *PVBOXGUESTWINBASEADDRESS;
101
102
103/**
104 * Subclassing the device extension for adding windows-specific bits.
105 */
106typedef struct VBOXGUESTDEVEXTWIN
107{
108 /** The common device extension core. */
109 VBOXGUESTDEVEXT Core;
110
111 /** Our functional driver object. */
112 PDEVICE_OBJECT pDeviceObject;
113 /** Top of the stack. */
114 PDEVICE_OBJECT pNextLowerDriver;
115 /** Interrupt object pointer. */
116 PKINTERRUPT pInterruptObject;
117
118 /** Bus number where the device is located. */
119 ULONG uBus;
120 /** Slot number where the device is located. */
121 ULONG uSlot;
122 /** Device interrupt level. */
123 ULONG uInterruptLevel;
124 /** Device interrupt vector. */
125 ULONG uInterruptVector;
126 /** Affinity mask. */
127 KAFFINITY fInterruptAffinity;
128 /** LevelSensitive or Latched. */
129 KINTERRUPT_MODE enmInterruptMode;
130
131 /** PCI base address information. */
132 ULONG cPciAddresses;
133 VBOXGUESTWINBASEADDRESS aPciBaseAddresses[PCI_TYPE0_ADDRESSES];
134
135 /** Physical address and length of VMMDev memory. */
136 PHYSICAL_ADDRESS uVmmDevMemoryPhysAddr;
137 /** Length of VMMDev memory. */
138 ULONG cbVmmDevMemory;
139
140 /** Device state. */
141 VGDRVNTDEVSTATE enmDevState;
142 /** The previous device state. */
143 VGDRVNTDEVSTATE enmPrevDevState;
144
145 /** Last system power action set (see VBoxGuestPower). */
146 POWER_ACTION enmLastSystemPowerAction;
147 /** Preallocated generic request for shutdown. */
148 VMMDevPowerStateRequest *pPowerStateRequest;
149
150 /** Spinlock protecting MouseNotifyCallback. Required since the consumer is
151 * in a DPC callback and not the ISR. */
152 KSPIN_LOCK MouseEventAccessSpinLock;
153} VBOXGUESTDEVEXTWIN;
154typedef VBOXGUESTDEVEXTWIN *PVBOXGUESTDEVEXTWIN;
155
156
157/** NT (windows) version identifier. */
158typedef enum VGDRVNTVER
159{
160 VGDRVNTVER_INVALID = 0,
161 VGDRVNTVER_WINNT310,
162 VGDRVNTVER_WINNT350,
163 VGDRVNTVER_WINNT351,
164 VGDRVNTVER_WINNT4,
165 VGDRVNTVER_WIN2K,
166 VGDRVNTVER_WINXP,
167 VGDRVNTVER_WIN2K3,
168 VGDRVNTVER_WINVISTA,
169 VGDRVNTVER_WIN7,
170 VGDRVNTVER_WIN8,
171 VGDRVNTVER_WIN81,
172 VGDRVNTVER_WIN10
173} VGDRVNTVER;
174
175
176/*********************************************************************************************************************************
177* Internal Functions *
178*********************************************************************************************************************************/
179RT_C_DECLS_BEGIN
180#ifdef TARGET_NT4
181static NTSTATUS vgdrvNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
182static NTSTATUS vgdrvNt4FindPciDevice(PULONG puluBusNumber, PPCI_SLOT_NUMBER puSlotNumber);
183#endif
184static NTSTATUS vgdrvNtNt5PlusAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj);
185static NTSTATUS vgdrvNtNt5PlusPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp);
186static NTSTATUS vgdrvNtNt5PlusPower(PDEVICE_OBJECT pDevObj, PIRP pIrp);
187static NTSTATUS vgdrvNtNt5PlusSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
188static void vgdrvNtUnmapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt);
189static void vgdrvNtUnload(PDRIVER_OBJECT pDrvObj);
190static NTSTATUS vgdrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
191static NTSTATUS vgdrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
192static NTSTATUS vgdrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
193static NTSTATUS vgdrvNtDeviceControlSlow(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
194static NTSTATUS vgdrvNtInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
195static void vgdrvNtReadConfiguration(PVBOXGUESTDEVEXTWIN pDevExt);
196static NTSTATUS vgdrvNtShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp);
197static NTSTATUS vgdrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
198static VOID NTAPI vgdrvNtBugCheckCallback(PVOID pvBuffer, ULONG cbBuffer);
199#ifdef VBOX_STRICT
200static void vgdrvNtDoTests(void);
201#endif
202static VOID vgdrvNtDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext);
203static BOOLEAN vgdrvNtIsrHandler(PKINTERRUPT interrupt, PVOID serviceContext);
204static NTSTATUS vgdrvNtScanPCIResourceList(PVBOXGUESTDEVEXTWIN pDevExt, PCM_RESOURCE_LIST pResList, bool fTranslated);
205static NTSTATUS vgdrvNtMapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS PhysAddr, ULONG cbToMap,
206 void **ppvMMIOBase, uint32_t *pcbMMIO);
207RT_C_DECLS_END
208
209
210/*********************************************************************************************************************************
211* Exported Functions *
212*********************************************************************************************************************************/
213RT_C_DECLS_BEGIN
214NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
215RT_C_DECLS_END
216
217#ifdef ALLOC_PRAGMA
218/* We only do INIT allocations. PAGE is too much work and risk for little gain. */
219# pragma alloc_text(INIT, DriverEntry)
220# ifdef TARGET_NT4
221# pragma alloc_text(INIT, vgdrvNt4CreateDevice)
222# pragma alloc_text(INIT, vgdrvNt4FindPciDevice)
223# endif
224#endif
225
226
227/*********************************************************************************************************************************
228* Global Variables *
229*********************************************************************************************************************************/
230/** The detected NT (windows) version. */
231static VGDRVNTVER g_enmVGDrvNtVer = VGDRVNTVER_INVALID;
232/** Pointer to the PoStartNextPowerIrp routine (in the NT kernel).
233 * Introduced in Windows 2000. */
234static decltype(PoStartNextPowerIrp) *g_pfnPoStartNextPowerIrp = NULL;
235/** Pointer to the PoCallDriver routine (in the NT kernel).
236 * Introduced in Windows 2000. */
237static decltype(PoCallDriver) *g_pfnPoCallDriver = NULL;
238/** Pointer to the KeRegisterBugCheckCallback routine (in the NT kernel).
239 * Introduced in Windows 3.50. */
240static decltype(KeRegisterBugCheckCallback) *g_pfnKeRegisterBugCheckCallback = NULL;
241/** Pointer to the KeRegisterBugCheckCallback routine (in the NT kernel).
242 * Introduced in Windows 3.50. */
243static decltype(KeDeregisterBugCheckCallback) *g_pfnKeDeregisterBugCheckCallback = NULL;
244/** Pointer to the KiBugCheckData array (in the NT kernel).
245 * Introduced in Windows 4. */
246static uintptr_t const *g_pauKiBugCheckData = NULL;
247/** Set if the callback was successfully registered and needs deregistering. */
248static bool g_fBugCheckCallbackRegistered = false;
249/** The bugcheck callback record. */
250static KBUGCHECK_CALLBACK_RECORD g_BugCheckCallbackRec;
251
252/**
253 * Driver entry point.
254 *
255 * @returns appropriate status code.
256 * @param pDrvObj Pointer to driver object.
257 * @param pRegPath Registry base path.
258 */
259NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
260{
261 RT_NOREF1(pRegPath);
262
263 /*
264 * Start by initializing IPRT.
265 */
266 int rc = RTR0Init(0);
267 if (RT_FAILURE(rc))
268 {
269 RTLogBackdoorPrintf("VBoxGuest: RTR0Init failed: %Rrc!\n", rc);
270 return STATUS_UNSUCCESSFUL;
271 }
272 VGDrvCommonInitLoggers();
273
274 LogFunc(("Driver built: %s %s\n", __DATE__, __TIME__));
275
276 /*
277 * Check if the NT version is supported and initialize g_enmVGDrvNtVer.
278 */
279 ULONG ulMajorVer;
280 ULONG ulMinorVer;
281 ULONG ulBuildNo;
282 BOOLEAN fCheckedBuild = PsGetVersion(&ulMajorVer, &ulMinorVer, &ulBuildNo, NULL);
283
284 /* Use RTLogBackdoorPrintf to make sure that this goes to VBox.log on the host. */
285 RTLogBackdoorPrintf("VBoxGuest: Windows version %u.%u, build %u\n", ulMajorVer, ulMinorVer, ulBuildNo);
286 if (fCheckedBuild)
287 RTLogBackdoorPrintf("VBoxGuest: Windows checked build\n");
288
289#ifdef VBOX_STRICT
290 vgdrvNtDoTests();
291#endif
292 NTSTATUS rcNt = STATUS_SUCCESS;
293 switch (ulMajorVer)
294 {
295 case 10: /* Windows 10 Preview builds starting with 9926. */
296 g_enmVGDrvNtVer = VGDRVNTVER_WIN10;
297 break;
298 case 6: /* Windows Vista or Windows 7 (based on minor ver) */
299 switch (ulMinorVer)
300 {
301 case 0: /* Note: Also could be Windows 2008 Server! */
302 g_enmVGDrvNtVer = VGDRVNTVER_WINVISTA;
303 break;
304 case 1: /* Note: Also could be Windows 2008 Server R2! */
305 g_enmVGDrvNtVer = VGDRVNTVER_WIN7;
306 break;
307 case 2:
308 g_enmVGDrvNtVer = VGDRVNTVER_WIN8;
309 break;
310 case 3:
311 g_enmVGDrvNtVer = VGDRVNTVER_WIN81;
312 break;
313 case 4: /* Windows 10 Preview builds. */
314 default:
315 g_enmVGDrvNtVer = VGDRVNTVER_WIN10;
316 break;
317 }
318 break;
319 case 5:
320 switch (ulMinorVer)
321 {
322 default:
323 case 2:
324 g_enmVGDrvNtVer = VGDRVNTVER_WIN2K3;
325 break;
326 case 1:
327 g_enmVGDrvNtVer = VGDRVNTVER_WINXP;
328 break;
329 case 0:
330 g_enmVGDrvNtVer = VGDRVNTVER_WIN2K;
331 break;
332 }
333 break;
334 case 4:
335 g_enmVGDrvNtVer = VGDRVNTVER_WINNT4;
336 break;
337 case 3:
338 if (ulMinorVer > 50)
339 g_enmVGDrvNtVer = VGDRVNTVER_WINNT351;
340 else if (ulMinorVer >= 50)
341 g_enmVGDrvNtVer = VGDRVNTVER_WINNT350;
342 else
343 g_enmVGDrvNtVer = VGDRVNTVER_WINNT310;
344 break;
345 default:
346 /* Major versions above 6 gets classified as windows 10. */
347 if (ulMajorVer > 6)
348 g_enmVGDrvNtVer = VGDRVNTVER_WIN10;
349 else
350 {
351 LogRelFunc(("At least Windows NT 3.10 required! Found %u.%u!\n", ulMajorVer, ulMinorVer));
352 rcNt = STATUS_DRIVER_UNABLE_TO_LOAD;
353 }
354 break;
355 }
356 if (NT_SUCCESS(rcNt))
357 {
358 /*
359 * Dynamically resolve symbols not present in NT4.
360 */
361 RTDBGKRNLINFO hKrnlInfo;
362 int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0 /*fFlags*/);
363 if (RT_SUCCESS(rc))
364 {
365 g_pfnKeRegisterBugCheckCallback = (decltype(KeRegisterBugCheckCallback) *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeRegisterBugCheckCallback");
366 g_pfnKeDeregisterBugCheckCallback = (decltype(KeDeregisterBugCheckCallback) *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeDeregisterBugCheckCallback");
367 g_pauKiBugCheckData = (uintptr_t const *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KiBugCheckData");
368 g_pfnPoCallDriver = (decltype(PoCallDriver) *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "PoCallDriver");
369 g_pfnPoStartNextPowerIrp = (decltype(PoStartNextPowerIrp) *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "PoStartNextPowerIrp");
370#ifdef TARGET_NT4
371 if (g_enmVGDrvNtVer > VGDRVNTVER_WINNT4)
372#endif
373 {
374 if (!g_pfnPoCallDriver) { LogRelFunc(("Missing PoCallDriver!\n")); rc = VERR_SYMBOL_NOT_FOUND; }
375 if (!g_pfnPoStartNextPowerIrp) { LogRelFunc(("Missing PoStartNextPowerIrp!\n")); rc = VERR_SYMBOL_NOT_FOUND; }
376 }
377
378 RTR0DbgKrnlInfoRelease(hKrnlInfo);
379 }
380 if (RT_SUCCESS(rc))
381 {
382 /*
383 * Setup the driver entry points in pDrvObj.
384 */
385 pDrvObj->DriverUnload = vgdrvNtUnload;
386 pDrvObj->MajorFunction[IRP_MJ_CREATE] = vgdrvNtCreate;
387 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = vgdrvNtClose;
388 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vgdrvNtDeviceControl;
389 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = vgdrvNtInternalIOCtl;
390 pDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = vgdrvNtShutdown;
391 pDrvObj->MajorFunction[IRP_MJ_READ] = vgdrvNtNotSupportedStub;
392 pDrvObj->MajorFunction[IRP_MJ_WRITE] = vgdrvNtNotSupportedStub;
393#ifdef TARGET_NT4
394 if (g_enmVGDrvNtVer <= VGDRVNTVER_WINNT4)
395 rcNt = vgdrvNt4CreateDevice(pDrvObj, pRegPath);
396 else
397#endif
398 {
399 pDrvObj->MajorFunction[IRP_MJ_PNP] = vgdrvNtNt5PlusPnP;
400 pDrvObj->MajorFunction[IRP_MJ_POWER] = vgdrvNtNt5PlusPower;
401 pDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = vgdrvNtNt5PlusSystemControl;
402 pDrvObj->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)vgdrvNtNt5PlusAddDevice;
403 }
404 if (NT_SUCCESS(rcNt))
405 {
406 /*
407 * Try register the bugcheck callback (non-fatal).
408 */
409 if ( g_pfnKeRegisterBugCheckCallback
410 && g_pfnKeDeregisterBugCheckCallback)
411 {
412 AssertCompile(BufferEmpty == 0);
413 KeInitializeCallbackRecord(&g_BugCheckCallbackRec);
414 if (g_pfnKeRegisterBugCheckCallback(&g_BugCheckCallbackRec, vgdrvNtBugCheckCallback,
415 NULL, 0, (PUCHAR)"VBoxGuest"))
416 g_fBugCheckCallbackRegistered = true;
417 else
418 g_fBugCheckCallbackRegistered = false;
419 }
420 else
421 Assert(g_pfnKeRegisterBugCheckCallback == NULL && g_pfnKeDeregisterBugCheckCallback);
422
423 LogFlowFunc(("Returning %#x\n", rcNt));
424 return rcNt;
425 }
426 }
427 else
428 rcNt = STATUS_PROCEDURE_NOT_FOUND;
429 }
430
431 /*
432 * Failed.
433 */
434 LogRelFunc(("Failed! rcNt=%#x\n", rcNt));
435 VGDrvCommonDestroyLoggers();
436 RTR0Term();
437 return rcNt;
438}
439
440
441/**
442 * Translates our internal NT version enum to VBox OS.
443 *
444 * @returns VBox OS type.
445 * @param enmNtVer The NT version.
446 */
447static VBOXOSTYPE vgdrvNtVersionToOSType(VGDRVNTVER enmNtVer)
448{
449 VBOXOSTYPE enmOsType;
450 switch (enmNtVer)
451 {
452 case VGDRVNTVER_WINNT310: enmOsType = VBOXOSTYPE_WinNT3x; break;
453 case VGDRVNTVER_WINNT350: enmOsType = VBOXOSTYPE_WinNT3x; break;
454 case VGDRVNTVER_WINNT351: enmOsType = VBOXOSTYPE_WinNT3x; break;
455 case VGDRVNTVER_WINNT4: enmOsType = VBOXOSTYPE_WinNT4; break;
456 case VGDRVNTVER_WIN2K: enmOsType = VBOXOSTYPE_Win2k; break;
457 case VGDRVNTVER_WINXP: enmOsType = VBOXOSTYPE_WinXP; break;
458 case VGDRVNTVER_WIN2K3: enmOsType = VBOXOSTYPE_Win2k3; break;
459 case VGDRVNTVER_WINVISTA: enmOsType = VBOXOSTYPE_WinVista; break;
460 case VGDRVNTVER_WIN7: enmOsType = VBOXOSTYPE_Win7; break;
461 case VGDRVNTVER_WIN8: enmOsType = VBOXOSTYPE_Win8; break;
462 case VGDRVNTVER_WIN81: enmOsType = VBOXOSTYPE_Win81; break;
463 case VGDRVNTVER_WIN10: enmOsType = VBOXOSTYPE_Win10; break;
464
465 default:
466 /* We don't know, therefore NT family. */
467 enmOsType = VBOXOSTYPE_WinNT;
468 break;
469 }
470#if ARCH_BITS == 64
471 enmOsType = (VBOXOSTYPE)((int)enmOsType | VBOXOSTYPE_x64);
472#endif
473 return enmOsType;
474}
475
476
477#ifdef LOG_ENABLED
478/**
479 * Debug helper to dump a device resource list.
480 *
481 * @param pResourceList list of device resources.
482 */
483static void vgdrvNtShowDeviceResources(PCM_RESOURCE_LIST pRsrcList)
484{
485 for (uint32_t iList = 0; iList < pRsrcList->Count; iList++)
486 {
487 PCM_FULL_RESOURCE_DESCRIPTOR pList = &pRsrcList->List[iList];
488 LogFunc(("List #%u: InterfaceType=%#x BusNumber=%#x ListCount=%u ListRev=%#x ListVer=%#x\n",
489 iList, pList->InterfaceType, pList->BusNumber, pList->PartialResourceList.Count,
490 pList->PartialResourceList.Revision, pList->PartialResourceList.Version ));
491
492 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResource = pList->PartialResourceList.PartialDescriptors;
493 for (ULONG i = 0; i < pList->PartialResourceList.Count; ++i, ++pResource)
494 {
495 ULONG uType = pResource->Type;
496 static char const * const s_apszName[] =
497 {
498 "CmResourceTypeNull",
499 "CmResourceTypePort",
500 "CmResourceTypeInterrupt",
501 "CmResourceTypeMemory",
502 "CmResourceTypeDma",
503 "CmResourceTypeDeviceSpecific",
504 "CmResourceTypeuBusNumber",
505 "CmResourceTypeDevicePrivate",
506 "CmResourceTypeAssignedResource",
507 "CmResourceTypeSubAllocateFrom",
508 };
509
510 if (uType < RT_ELEMENTS(s_apszName))
511 LogFunc((" %.30s Flags=%#x Share=%#x", s_apszName[uType], pResource->Flags, pResource->ShareDisposition));
512 else
513 LogFunc((" Type=%#x Flags=%#x Share=%#x", uType, pResource->Flags, pResource->ShareDisposition));
514 switch (uType)
515 {
516 case CmResourceTypePort:
517 case CmResourceTypeMemory:
518 Log((" Start %#RX64, length=%#x\n", pResource->u.Port.Start.QuadPart, pResource->u.Port.Length));
519 break;
520
521 case CmResourceTypeInterrupt:
522 Log((" Level=%X, vector=%#x, affinity=%#x\n",
523 pResource->u.Interrupt.Level, pResource->u.Interrupt.Vector, pResource->u.Interrupt.Affinity));
524 break;
525
526 case CmResourceTypeDma:
527 Log((" Channel %d, Port %#x\n", pResource->u.Dma.Channel, pResource->u.Dma.Port));
528 break;
529
530 default:
531 Log(("\n"));
532 break;
533 }
534 }
535 }
536}
537#endif /* LOG_ENABLED */
538
539
540/**
541 * Sets up the device and its resources.
542 *
543 * @param pDevExt Our device extension data.
544 * @param pDevObj The device object.
545 * @param pIrp The request packet if NT5+, NULL for NT4 and earlier.
546 * @param pDrvObj The driver object for NT4, NULL for NT5+.
547 * @param pRegPath The registry path for NT4, NULL for NT5+.
548 */
549static NTSTATUS vgdrvNtSetupDevice(PVBOXGUESTDEVEXTWIN pDevExt, PDEVICE_OBJECT pDevObj,
550 PIRP pIrp, PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
551{
552 LogFlowFunc(("ENTER: pDevExt=%p pDevObj=%p pIrq=%p pDrvObj=%p pRegPath=%p\n", pDevExt, pDevObj, pIrp, pDrvObj, pRegPath));
553
554 NTSTATUS rcNt;
555 if (!pIrp)
556 {
557#ifdef TARGET_NT4
558 /*
559 * NT4: Let's have a look at what our PCI adapter offers.
560 */
561 LogFlowFunc(("Starting to scan PCI resources of VBoxGuest ...\n"));
562
563 /* Assign the PCI resources. */
564 UNICODE_STRING ClassName;
565 RtlInitUnicodeString(&ClassName, L"VBoxGuestAdapter");
566 PCM_RESOURCE_LIST pResourceList = NULL;
567 rcNt = HalAssignSlotResources(pRegPath, &ClassName, pDrvObj, pDevObj, PCIBus, pDevExt->uBus, pDevExt->uSlot,
568 &pResourceList);
569# ifdef LOG_ENABLED
570 if (pResourceList)
571 vgdrvNtShowDeviceResources(pResourceList);
572# endif
573 if (NT_SUCCESS(rcNt))
574 {
575 rcNt = vgdrvNtScanPCIResourceList(pDevExt, pResourceList, false /*fTranslated*/);
576 ExFreePool(pResourceList);
577 }
578
579# else /* !TARGET_NT4 */
580 AssertFailed();
581 RT_NOREF(pDevObj, pDrvObj, pRegPath);
582 rcNt = STATUS_INTERNAL_ERROR;
583# endif /* !TARGET_NT4 */
584 }
585 else
586 {
587 /*
588 * NT5+: Scan the PCI resource list from the IRP.
589 */
590 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
591# ifdef LOG_ENABLED
592 vgdrvNtShowDeviceResources(pStack->Parameters.StartDevice.AllocatedResources);
593# endif
594 rcNt = vgdrvNtScanPCIResourceList(pDevExt, pStack->Parameters.StartDevice.AllocatedResourcesTranslated,
595 true /*fTranslated*/);
596 }
597 if (NT_SUCCESS(rcNt))
598 {
599 /*
600 * Map physical address of VMMDev memory into MMIO region
601 * and init the common device extension bits.
602 */
603 void *pvMMIOBase = NULL;
604 uint32_t cbMMIO = 0;
605 rcNt = vgdrvNtMapVMMDevMemory(pDevExt,
606 pDevExt->uVmmDevMemoryPhysAddr,
607 pDevExt->cbVmmDevMemory,
608 &pvMMIOBase,
609 &cbMMIO);
610 if (NT_SUCCESS(rcNt))
611 {
612 pDevExt->Core.pVMMDevMemory = (VMMDevMemory *)pvMMIOBase;
613
614 LogFunc(("pvMMIOBase=0x%p, pDevExt=0x%p, pDevExt->Core.pVMMDevMemory=0x%p\n",
615 pvMMIOBase, pDevExt, pDevExt ? pDevExt->Core.pVMMDevMemory : NULL));
616
617 int vrc = VGDrvCommonInitDevExtResources(&pDevExt->Core,
618 pDevExt->Core.IOPortBase,
619 pvMMIOBase, cbMMIO,
620 vgdrvNtVersionToOSType(g_enmVGDrvNtVer),
621 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
622 if (RT_SUCCESS(vrc))
623 {
624
625 vrc = VbglR0GRAlloc((VMMDevRequestHeader **)&pDevExt->pPowerStateRequest,
626 sizeof(VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
627 if (RT_SUCCESS(vrc))
628 {
629 /*
630 * Register DPC and ISR.
631 */
632 LogFlowFunc(("Initializing DPC/ISR (pDevObj=%p)...\n", pDevExt->pDeviceObject));
633 IoInitializeDpcRequest(pDevExt->pDeviceObject, vgdrvNtDpcHandler);
634
635 ULONG uInterruptVector = pDevExt->uInterruptVector;
636 KIRQL uHandlerIrql = (KIRQL)pDevExt->uInterruptLevel;
637#ifdef TARGET_NT4
638 if (!pIrp)
639 {
640 /* NT4: Get an interrupt vector. Only proceed if the device provides an interrupt. */
641 if ( uInterruptVector
642 || pDevExt->uInterruptLevel)
643 {
644 LogFlowFunc(("Getting interrupt vector (HAL): Bus=%u, IRQL=%u, Vector=%u\n",
645 pDevExt->uBus, pDevExt->uInterruptLevel, pDevExt->uInterruptVector));
646 uInterruptVector = HalGetInterruptVector(PCIBus,
647 pDevExt->uBus,
648 pDevExt->uInterruptLevel,
649 pDevExt->uInterruptVector,
650 &uHandlerIrql,
651 &pDevExt->fInterruptAffinity);
652 LogFlowFunc(("HalGetInterruptVector returns vector=%u\n", uInterruptVector));
653 }
654 else
655 LogFunc(("Device does not provide an interrupt!\n"));
656 }
657#endif
658 if (uInterruptVector)
659 {
660 LogFlowFunc(("Connecting interrupt (IntVector=%#u), uHandlerIrql=%u) ...\n",
661 uInterruptVector, uHandlerIrql));
662
663 rcNt = IoConnectInterrupt(&pDevExt->pInterruptObject, /* Out: interrupt object. */
664 vgdrvNtIsrHandler, /* Our ISR handler. */
665 pDevExt, /* Device context. */
666 NULL, /* Optional spinlock. */
667 uInterruptVector, /* Interrupt vector. */
668 uHandlerIrql, /* Irql. */
669 uHandlerIrql, /* SynchronizeIrql. */
670 pDevExt->enmInterruptMode, /* LevelSensitive or Latched. */
671 TRUE, /* Shareable interrupt. */
672 pDevExt->fInterruptAffinity, /* CPU affinity. */
673 FALSE); /* Don't save FPU stack. */
674 if (NT_ERROR(rcNt))
675 LogFunc(("Could not connect interrupt: rcNt=%#x!\n", rcNt));
676 }
677 else
678 LogFunc(("No interrupt vector found!\n"));
679 if (NT_SUCCESS(rcNt))
680 {
681 /*
682 * Once we've read configuration from register and host, we're finally read.
683 */
684 /** @todo clean up guest ring-3 logging, keeping it separate from the kernel to avoid sharing limits with it. */
685 pDevExt->Core.fLoggingEnabled = true;
686 vgdrvNtReadConfiguration(pDevExt);
687
688 /* Ready to rumble! */
689 LogRelFunc(("Device is ready!\n"));
690 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_WORKING);
691 return STATUS_SUCCESS;
692 }
693 pDevExt->pInterruptObject = NULL;
694
695 VbglR0GRFree(&pDevExt->pPowerStateRequest->header);
696 pDevExt->pPowerStateRequest = NULL;
697 }
698 else
699 {
700 LogFunc(("Alloc for pPowerStateRequest failed, vrc=%Rrc\n", vrc));
701 rcNt = STATUS_UNSUCCESSFUL;
702 }
703
704 VGDrvCommonDeleteDevExtResources(&pDevExt->Core);
705 }
706 else
707 {
708 LogFunc(("Could not init device extension resources: vrc=%Rrc\n", vrc));
709 rcNt = STATUS_DEVICE_CONFIGURATION_ERROR;
710 }
711 vgdrvNtUnmapVMMDevMemory(pDevExt);
712 }
713 else
714 LogFunc(("Could not map physical address of VMMDev, rcNt=%#x\n", rcNt));
715 }
716
717 LogFunc(("Returned with rcNt=%#x\n", rcNt));
718 return rcNt;
719}
720
721
722
723
724#ifdef TARGET_NT4
725
726/**
727 * Helper function to handle the PCI device lookup.
728 *
729 * @returns NT status code.
730 *
731 * @param puBus Where to return the bus number on success.
732 * @param pSlot Where to return the slot number on success.
733 */
734static NTSTATUS vgdrvNt4FindPciDevice(PULONG puBus, PPCI_SLOT_NUMBER pSlot)
735{
736 Log(("vgdrvNt4FindPciDevice\n"));
737
738 PCI_SLOT_NUMBER Slot;
739 Slot.u.AsULONG = 0;
740
741 /* Scan each bus. */
742 for (ULONG uBus = 0; uBus < PCI_MAX_BUSES; uBus++)
743 {
744 /* Scan each device. */
745 for (ULONG deviceNumber = 0; deviceNumber < PCI_MAX_DEVICES; deviceNumber++)
746 {
747 Slot.u.bits.DeviceNumber = deviceNumber;
748
749 /* Scan each function (not really required...). */
750 for (ULONG functionNumber = 0; functionNumber < PCI_MAX_FUNCTION; functionNumber++)
751 {
752 Slot.u.bits.FunctionNumber = functionNumber;
753
754 /* Have a look at what's in this slot. */
755 PCI_COMMON_CONFIG PciData;
756 if (!HalGetBusData(PCIConfiguration, uBus, Slot.u.AsULONG, &PciData, sizeof(ULONG)))
757 {
758 /* No such bus, we're done with it. */
759 deviceNumber = PCI_MAX_DEVICES;
760 break;
761 }
762
763 if (PciData.VendorID == PCI_INVALID_VENDORID)
764 /* We have to proceed to the next function. */
765 continue;
766
767 /* Check if it's another device. */
768 if ( PciData.VendorID != VMMDEV_VENDORID
769 || PciData.DeviceID != VMMDEV_DEVICEID)
770 continue;
771
772 /* Hooray, we've found it! */
773 Log(("vgdrvNt4FindPciDevice: Device found! Bus=%#x Slot=%#u (dev %#x, fun %#x, rvd %#x)\n",
774 uBus, Slot.u.AsULONG, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber, Slot.u.bits.Reserved));
775
776 *puBus = uBus;
777 *pSlot = Slot;
778 return STATUS_SUCCESS;
779 }
780 }
781 }
782
783 return STATUS_DEVICE_DOES_NOT_EXIST;
784}
785
786
787/**
788 * Legacy helper function to create the device object.
789 *
790 * @returns NT status code.
791 *
792 * @param pDrvObj The driver object.
793 * @param pRegPath The driver registry path.
794 */
795static NTSTATUS vgdrvNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
796{
797 Log(("vgdrvNt4CreateDevice: pDrvObj=%p, pRegPath=%p\n", pDrvObj, pRegPath));
798
799 /*
800 * Find our virtual PCI device
801 */
802 ULONG uBus;
803 PCI_SLOT_NUMBER uSlot;
804 NTSTATUS rc = vgdrvNt4FindPciDevice(&uBus, &uSlot);
805 if (NT_ERROR(rc))
806 {
807 Log(("vgdrvNt4CreateDevice: Device not found!\n"));
808 return rc;
809 }
810
811 /*
812 * Create device.
813 */
814 UNICODE_STRING DevName;
815 RtlInitUnicodeString(&DevName, VBOXGUEST_DEVICE_NAME_NT);
816 PDEVICE_OBJECT pDeviceObject = NULL;
817 rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
818 if (NT_SUCCESS(rc))
819 {
820 Log(("vgdrvNt4CreateDevice: Device created\n"));
821
822 UNICODE_STRING DosName;
823 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
824 rc = IoCreateSymbolicLink(&DosName, &DevName);
825 if (NT_SUCCESS(rc))
826 {
827 Log(("vgdrvNt4CreateDevice: Symlink created\n"));
828
829 /*
830 * Setup the device extension.
831 */
832 Log(("vgdrvNt4CreateDevice: Setting up device extension ...\n"));
833 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
834 RT_ZERO(*pDevExt);
835
836 /* Store a reference to ourself. */
837 pDevExt->pDeviceObject = pDeviceObject;
838
839 /* Store bus and slot number we've queried before. */
840 pDevExt->uBus = uBus;
841 pDevExt->uSlot = uSlot.u.AsULONG;
842
843 /* Initialize common bits. */
844 int vrc = VGDrvCommonInitDevExtFundament(&pDevExt->Core);
845 if (RT_SUCCESS(vrc))
846 {
847 Log(("vgdrvNt4CreateDevice: Device extension created\n"));
848
849 /* Do the actual VBox init ... */
850 rc = vgdrvNtSetupDevice(pDevExt, pDeviceObject, NULL /*pIrp*/, pDrvObj, pRegPath);
851 if (NT_SUCCESS(rc))
852 {
853 Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x (succcess)\n", rc));
854 return rc;
855 }
856
857 /* bail out */
858 VGDrvCommonDeleteDevExtFundament(&pDevExt->Core);
859 }
860 IoDeleteSymbolicLink(&DosName);
861 }
862 else
863 Log(("vgdrvNt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc));
864 IoDeleteDevice(pDeviceObject);
865 }
866 else
867 Log(("vgdrvNt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc));
868 Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x\n", rc));
869 return rc;
870}
871
872#endif /* TARGET_NT4 */
873
874/**
875 * Handle request from the Plug & Play subsystem.
876 *
877 * @returns NT status code
878 * @param pDrvObj Driver object
879 * @param pDevObj Device object
880 *
881 * @remarks Parts of this is duplicated in VBoxGuest-win-legacy.cpp.
882 */
883static NTSTATUS vgdrvNtNt5PlusAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
884{
885 LogFlowFuncEnter();
886
887 /*
888 * Create device.
889 */
890 UNICODE_STRING DevName;
891 RtlInitUnicodeString(&DevName, VBOXGUEST_DEVICE_NAME_NT);
892 PDEVICE_OBJECT pDeviceObject = NULL;
893 NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
894 if (NT_SUCCESS(rcNt))
895 {
896 /*
897 * Create symbolic link (DOS devices).
898 */
899 UNICODE_STRING DosName;
900 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
901 rcNt = IoCreateSymbolicLink(&DosName, &DevName);
902 if (NT_SUCCESS(rcNt))
903 {
904 /*
905 * Setup the device extension.
906 */
907 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
908 RT_ZERO(*pDevExt);
909
910 KeInitializeSpinLock(&pDevExt->MouseEventAccessSpinLock);
911 pDevExt->pDeviceObject = pDeviceObject;
912 pDevExt->enmPrevDevState = VGDRVNTDEVSTATE_STOPPED;
913 pDevExt->enmDevState = VGDRVNTDEVSTATE_STOPPED;
914
915 int vrc = VGDrvCommonInitDevExtFundament(&pDevExt->Core);
916 if (RT_SUCCESS(vrc))
917 {
918 pDevExt->pNextLowerDriver = IoAttachDeviceToDeviceStack(pDeviceObject, pDevObj);
919 if (pDevExt->pNextLowerDriver != NULL)
920 {
921 /* Ensure we are not called at elevated IRQL, even if our code isn't pagable any more. */
922 pDeviceObject->Flags |= DO_POWER_PAGABLE;
923
924 /* Driver is ready now. */
925 pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
926 LogFlowFunc(("Returning with rcNt=%#x (success)\n", rcNt));
927 return rcNt;
928 }
929
930 LogFunc(("IoAttachDeviceToDeviceStack did not give a nextLowerDriver!\n"));
931 rcNt = STATUS_DEVICE_NOT_CONNECTED;
932 VGDrvCommonDeleteDevExtFundament(&pDevExt->Core);
933 }
934 else
935 rcNt = STATUS_UNSUCCESSFUL;
936
937 /* bail out */
938 IoDeleteSymbolicLink(&DosName);
939 }
940 else
941 LogFunc(("IoCreateSymbolicLink failed with rcNt=%#x!\n", rcNt));
942 IoDeleteDevice(pDeviceObject);
943 }
944 else
945 LogFunc(("IoCreateDevice failed with rcNt=%#x!\n", rcNt));
946
947 LogFunc(("Returning with rcNt=%#x\n", rcNt));
948 return rcNt;
949}
950
951
952/**
953 * Irp completion routine for PnP Irps we send.
954 *
955 * @returns NT status code.
956 * @param pDevObj Device object.
957 * @param pIrp Request packet.
958 * @param pEvent Semaphore.
959 */
960static NTSTATUS vgdrvNt5PlusPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
961{
962 RT_NOREF2(pDevObj, pIrp);
963 KeSetEvent(pEvent, 0, FALSE);
964 return STATUS_MORE_PROCESSING_REQUIRED;
965}
966
967
968/**
969 * Helper to send a PnP IRP and wait until it's done.
970 *
971 * @returns NT status code.
972 * @param pDevObj Device object.
973 * @param pIrp Request packet.
974 * @param fStrict When set, returns an error if the IRP gives an error.
975 */
976static NTSTATUS vgdrvNt5PlusPnPSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
977{
978 KEVENT Event;
979
980 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
981
982 IoCopyCurrentIrpStackLocationToNext(pIrp);
983 IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vgdrvNt5PlusPnpIrpComplete, &Event, TRUE, TRUE, TRUE);
984
985 NTSTATUS rcNt = IoCallDriver(pDevObj, pIrp);
986 if (rcNt == STATUS_PENDING)
987 {
988 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
989 rcNt = pIrp->IoStatus.Status;
990 }
991
992 if ( !fStrict
993 && (rcNt == STATUS_NOT_SUPPORTED || rcNt == STATUS_INVALID_DEVICE_REQUEST))
994 {
995 rcNt = STATUS_SUCCESS;
996 }
997
998 Log(("vgdrvNt5PlusPnPSendIrpSynchronously: Returning %#x\n", rcNt));
999 return rcNt;
1000}
1001
1002
1003/**
1004 * Deletes the device hardware resources.
1005 *
1006 * Used during removal, stopping and legacy module unloading.
1007 *
1008 * @param pDevExt The device extension.
1009 */
1010static void vgdrvNtDeleteDeviceResources(PVBOXGUESTDEVEXTWIN pDevExt)
1011{
1012 if (pDevExt->pInterruptObject)
1013 {
1014 IoDisconnectInterrupt(pDevExt->pInterruptObject);
1015 pDevExt->pInterruptObject = NULL;
1016 }
1017 if (pDevExt->Core.uInitState == VBOXGUESTDEVEXT_INIT_STATE_RESOURCES)
1018 VGDrvCommonDeleteDevExtResources(&pDevExt->Core);
1019 vgdrvNtUnmapVMMDevMemory(pDevExt);
1020}
1021
1022
1023/**
1024 * Deletes the device extension fundament and unlinks the device
1025 *
1026 * Used during removal and legacy module unloading. Must have called
1027 * vgdrvNtDeleteDeviceResources.
1028 *
1029 * @param pDevObj Device object.
1030 * @param pDevExt The device extension.
1031 */
1032static void vgdrvNtDeleteDeviceFundamentAndUnlink(PDEVICE_OBJECT pDevObj, PVBOXGUESTDEVEXTWIN pDevExt)
1033{
1034 /*
1035 * Delete the remainder of the device extension.
1036 */
1037 pDevExt->pPowerStateRequest = NULL; /* Will be deleted by the following call. */
1038 VGDrvCommonDeleteDevExtFundament(&pDevExt->Core);
1039
1040 /*
1041 * Delete the DOS symlink to the device and finally the device itself.
1042 */
1043 UNICODE_STRING DosName;
1044 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
1045 IoDeleteSymbolicLink(&DosName);
1046
1047 Log(("vgdrvNtDeleteDeviceFundamentAndUnlink: Deleting device ...\n"));
1048 IoDeleteDevice(pDevObj);
1049}
1050
1051
1052/**
1053 * PnP Request handler.
1054 *
1055 * @param pDevObj Device object.
1056 * @param pIrp Request packet.
1057 */
1058static NTSTATUS vgdrvNtNt5PlusPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1059{
1060 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1061 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1062
1063#ifdef LOG_ENABLED
1064 static char const * const s_apszFnctName[] =
1065 {
1066 "IRP_MN_START_DEVICE",
1067 "IRP_MN_QUERY_REMOVE_DEVICE",
1068 "IRP_MN_REMOVE_DEVICE",
1069 "IRP_MN_CANCEL_REMOVE_DEVICE",
1070 "IRP_MN_STOP_DEVICE",
1071 "IRP_MN_QUERY_STOP_DEVICE",
1072 "IRP_MN_CANCEL_STOP_DEVICE",
1073 "IRP_MN_QUERY_DEVICE_RELATIONS",
1074 "IRP_MN_QUERY_INTERFACE",
1075 "IRP_MN_QUERY_CAPABILITIES",
1076 "IRP_MN_QUERY_RESOURCES",
1077 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
1078 "IRP_MN_QUERY_DEVICE_TEXT",
1079 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
1080 "IRP_MN_0xE",
1081 "IRP_MN_READ_CONFIG",
1082 "IRP_MN_WRITE_CONFIG",
1083 "IRP_MN_EJECT",
1084 "IRP_MN_SET_LOCK",
1085 "IRP_MN_QUERY_ID",
1086 "IRP_MN_QUERY_PNP_DEVICE_STATE",
1087 "IRP_MN_QUERY_BUS_INFORMATION",
1088 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
1089 "IRP_MN_SURPRISE_REMOVAL",
1090 };
1091 Log(("vgdrvNtNt5PlusPnP: MinorFunction: %s\n",
1092 pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName) ? s_apszFnctName[pStack->MinorFunction] : "Unknown"));
1093#endif
1094
1095 NTSTATUS rc = STATUS_SUCCESS;
1096 switch (pStack->MinorFunction)
1097 {
1098 case IRP_MN_START_DEVICE:
1099 {
1100 Log(("vgdrvNtNt5PlusPnP: START_DEVICE\n"));
1101
1102 /* This must be handled first by the lower driver. */
1103 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
1104 if ( NT_SUCCESS(rc)
1105 && NT_SUCCESS(pIrp->IoStatus.Status))
1106 {
1107 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
1108 pStack->Parameters.StartDevice.AllocatedResources));
1109 if (pStack->Parameters.StartDevice.AllocatedResources)
1110 {
1111 rc = vgdrvNtSetupDevice(pDevExt, pDevObj, pIrp, NULL, NULL);
1112 if (!NT_SUCCESS(rc))
1113 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: vgdrvNtSetupDevice failed: %#x\n", rc));
1114 }
1115 else
1116 {
1117 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
1118 pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL));
1119 rc = STATUS_UNSUCCESSFUL;
1120 }
1121 }
1122 else
1123 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: vgdrvNt5PlusPnPSendIrpSynchronously failed: %#x + %#x\n",
1124 rc, pIrp->IoStatus.Status));
1125
1126 pIrp->IoStatus.Status = rc;
1127 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1128 return rc;
1129 }
1130
1131
1132 /*
1133 * Sent before removing the device and/or driver.
1134 */
1135 case IRP_MN_QUERY_REMOVE_DEVICE:
1136 {
1137 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE\n"));
1138
1139#ifdef VBOX_REBOOT_ON_UNINSTALL
1140 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
1141 rc = STATUS_UNSUCCESSFUL;
1142#endif
1143 /** @todo refuse to remove ourselves when we've got client
1144 * sessions attached... */
1145
1146 if (NT_SUCCESS(rc))
1147 {
1148 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_PENDINGREMOVE);
1149
1150 /* This IRP passed down to lower driver. */
1151 pIrp->IoStatus.Status = STATUS_SUCCESS;
1152
1153 IoSkipCurrentIrpStackLocation(pIrp);
1154 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1155 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
1156
1157 /* We must not do anything the IRP after doing IoSkip & CallDriver
1158 since the driver below us will complete (or already have completed) the IRP.
1159 I.e. just return the status we got from IoCallDriver */
1160 }
1161 else
1162 {
1163 pIrp->IoStatus.Status = rc;
1164 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1165 }
1166
1167 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Returning with rc = 0x%x\n", rc));
1168 return rc;
1169 }
1170
1171 /*
1172 * Cancels a pending remove, IRP_MN_QUERY_REMOVE_DEVICE.
1173 * We only have to revert the state.
1174 */
1175 case IRP_MN_CANCEL_REMOVE_DEVICE:
1176 {
1177 Log(("vgdrvNtNt5PlusPnP: CANCEL_REMOVE_DEVICE\n"));
1178
1179 /* This must be handled first by the lower driver. */
1180 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
1181 if ( NT_SUCCESS(rc)
1182 && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGREMOVE)
1183 {
1184 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
1185 pDevExt->enmDevState = pDevExt->enmPrevDevState;
1186 }
1187
1188 /* Complete the IRP. */
1189 pIrp->IoStatus.Status = rc;
1190 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1191 return rc;
1192 }
1193
1194 /*
1195 * We do nothing here actually, esp. since this request is not expected for VBoxGuest.
1196 * The cleanup will be done in IRP_MN_REMOVE_DEVICE, which follows this call.
1197 */
1198 case IRP_MN_SURPRISE_REMOVAL:
1199 {
1200 Log(("vgdrvNtNt5PlusPnP: IRP_MN_SURPRISE_REMOVAL\n"));
1201 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_SURPRISEREMOVED);
1202 LogRel(("VBoxGuest: unexpected device removal\n"));
1203
1204 /* Pass to the lower driver. */
1205 pIrp->IoStatus.Status = STATUS_SUCCESS;
1206
1207 IoSkipCurrentIrpStackLocation(pIrp);
1208 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1209
1210 /* Do not complete the IRP. */
1211 return rc;
1212 }
1213
1214 /*
1215 * Device and/or driver removal. Destroy everything.
1216 */
1217 case IRP_MN_REMOVE_DEVICE:
1218 {
1219 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE\n"));
1220 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_REMOVED);
1221
1222 /*
1223 * Disconnect interrupts and delete all hardware resources.
1224 * Note! This may already have been done if we're STOPPED already, if that's a possibility.
1225 */
1226 vgdrvNtDeleteDeviceResources(pDevExt);
1227
1228 /*
1229 * We need to send the remove down the stack before we detach, but we don't need
1230 * to wait for the completion of this operation (nor register a completion routine).
1231 */
1232 pIrp->IoStatus.Status = STATUS_SUCCESS;
1233
1234 IoSkipCurrentIrpStackLocation(pIrp);
1235 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1236 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
1237
1238 IoDetachDevice(pDevExt->pNextLowerDriver);
1239 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Removing device ...\n"));
1240
1241 /*
1242 * Delete the remainder of the device extension data, unlink it from the namespace and delete it.
1243 */
1244 vgdrvNtDeleteDeviceFundamentAndUnlink(pDevObj, pDevExt);
1245
1246 pDevObj = NULL; /* invalid */
1247 pDevExt = NULL; /* invalid */
1248
1249 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Device removed!\n"));
1250 return rc; /* Propagating rc from IoCallDriver. */
1251 }
1252
1253
1254 /*
1255 * Sent before stopping the device/driver to check whether it is okay to do so.
1256 */
1257 case IRP_MN_QUERY_STOP_DEVICE:
1258 {
1259 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE\n"));
1260
1261 /** @todo Check whether we can stop the device. Similar to
1262 * removal above */
1263 rc = STATUS_SUCCESS;
1264 if (NT_SUCCESS(rc))
1265 {
1266 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_PENDINGSTOP);
1267
1268 /* This IRP passed down to lower driver. */
1269 pIrp->IoStatus.Status = STATUS_SUCCESS;
1270
1271 IoSkipCurrentIrpStackLocation(pIrp);
1272
1273 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1274 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
1275
1276 /* we must not do anything with the IRP after doing IoSkip & CallDriver since the
1277 driver below us will complete (or already have completed) the IRP. I.e. just
1278 return the status we got from IoCallDriver. */
1279 }
1280 else
1281 {
1282 pIrp->IoStatus.Status = rc;
1283 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1284 }
1285
1286 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE: Returning with rc = 0x%x\n", rc));
1287 return rc;
1288 }
1289
1290 /*
1291 * Cancels a pending remove, IRP_MN_QUERY_STOP_DEVICE.
1292 * We only have to revert the state.
1293 */
1294 case IRP_MN_CANCEL_STOP_DEVICE:
1295 {
1296 Log(("vgdrvNtNt5PlusPnP: CANCEL_STOP_DEVICE\n"));
1297
1298 /* This must be handled first by the lower driver. */
1299 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
1300 if ( NT_SUCCESS(rc)
1301 && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGSTOP)
1302 {
1303 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
1304 pDevExt->enmDevState = pDevExt->enmPrevDevState;
1305 }
1306
1307 /* Complete the IRP. */
1308 pIrp->IoStatus.Status = rc;
1309 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1310 return rc;
1311 }
1312
1313 /*
1314 * Stop the device.
1315 */
1316 case IRP_MN_STOP_DEVICE:
1317 {
1318 Log(("vgdrvNtNt5PlusPnP: STOP_DEVICE\n"));
1319 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_STOPPED);
1320
1321 /*
1322 * Release the hardware resources.
1323 */
1324 vgdrvNtDeleteDeviceResources(pDevExt);
1325
1326 /*
1327 * Pass the request to the lower driver.
1328 */
1329 pIrp->IoStatus.Status = STATUS_SUCCESS;
1330 IoSkipCurrentIrpStackLocation(pIrp);
1331 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1332 Log(("vgdrvNtNt5PlusPnP: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
1333 return rc;
1334 }
1335
1336 default:
1337 {
1338 IoSkipCurrentIrpStackLocation(pIrp);
1339 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1340 Log(("vgdrvNtNt5PlusPnP: Unknown request %#x: Lower driver replied: %x\n", pStack->MinorFunction, rc));
1341 return rc;
1342 }
1343 }
1344}
1345
1346
1347/**
1348 * Handle the power completion event.
1349 *
1350 * @returns NT status code.
1351 * @param pDevObj Targetted device object.
1352 * @param pIrp IO request packet.
1353 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
1354 */
1355static NTSTATUS vgdrvNtNt5PlusPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
1356{
1357#ifdef VBOX_STRICT
1358 RT_NOREF1(pDevObj);
1359 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pContext;
1360 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
1361
1362 Assert(pDevExt);
1363
1364 if (pIrpSp)
1365 {
1366 Assert(pIrpSp->MajorFunction == IRP_MJ_POWER);
1367 if (NT_SUCCESS(pIrp->IoStatus.Status))
1368 {
1369 switch (pIrpSp->MinorFunction)
1370 {
1371 case IRP_MN_SET_POWER:
1372 switch (pIrpSp->Parameters.Power.Type)
1373 {
1374 case DevicePowerState:
1375 switch (pIrpSp->Parameters.Power.State.DeviceState)
1376 {
1377 case PowerDeviceD0:
1378 break;
1379 default: /* Shut up MSC */
1380 break;
1381 }
1382 break;
1383 default: /* Shut up MSC */
1384 break;
1385 }
1386 break;
1387 }
1388 }
1389 }
1390#else
1391 RT_NOREF3(pDevObj, pIrp, pContext);
1392#endif
1393
1394 return STATUS_SUCCESS;
1395}
1396
1397
1398/**
1399 * Handle the Power requests.
1400 *
1401 * @returns NT status code
1402 * @param pDevObj device object
1403 * @param pIrp IRP
1404 */
1405static NTSTATUS vgdrvNtNt5PlusPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1406{
1407 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1408 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1409 POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
1410 POWER_STATE PowerState = pStack->Parameters.Power.State;
1411 POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
1412
1413 Log(("vgdrvNtNt5PlusPower:\n"));
1414
1415 switch (pStack->MinorFunction)
1416 {
1417 case IRP_MN_SET_POWER:
1418 {
1419 Log(("vgdrvNtNt5PlusPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
1420 switch (enmPowerType)
1421 {
1422 case SystemPowerState:
1423 {
1424 Log(("vgdrvNtNt5PlusPower: SystemPowerState, action = %d, state = %d/%d\n",
1425 enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
1426
1427 switch (enmPowerAction)
1428 {
1429 case PowerActionSleep:
1430
1431 /* System now is in a working state. */
1432 if (PowerState.SystemState == PowerSystemWorking)
1433 {
1434 if ( pDevExt
1435 && pDevExt->enmLastSystemPowerAction == PowerActionHibernate)
1436 {
1437 Log(("vgdrvNtNt5PlusPower: Returning from hibernation!\n"));
1438 int rc = VGDrvCommonReinitDevExtAfterHibernation(&pDevExt->Core,
1439 vgdrvNtVersionToOSType(g_enmVGDrvNtVer));
1440 if (RT_FAILURE(rc))
1441 Log(("vgdrvNtNt5PlusPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
1442 }
1443 }
1444 break;
1445
1446 case PowerActionShutdownReset:
1447 {
1448 Log(("vgdrvNtNt5PlusPower: Power action reset!\n"));
1449
1450 /* Tell the VMM that we no longer support mouse pointer integration. */
1451 VMMDevReqMouseStatus *pReq = NULL;
1452 int vrc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus),
1453 VMMDevReq_SetMouseStatus);
1454 if (RT_SUCCESS(vrc))
1455 {
1456 pReq->mouseFeatures = 0;
1457 pReq->pointerXPos = 0;
1458 pReq->pointerYPos = 0;
1459
1460 vrc = VbglR0GRPerform(&pReq->header);
1461 if (RT_FAILURE(vrc))
1462 {
1463 Log(("vgdrvNtNt5PlusPower: error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
1464 }
1465
1466 VbglR0GRFree(&pReq->header);
1467 }
1468
1469 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
1470 * power action and would assert/crash when we already cleaned up all the stuff! */
1471 break;
1472 }
1473
1474 case PowerActionShutdown:
1475 case PowerActionShutdownOff:
1476 {
1477 Log(("vgdrvNtNt5PlusPower: Power action shutdown!\n"));
1478 if (PowerState.SystemState >= PowerSystemShutdown)
1479 {
1480 Log(("vgdrvNtNt5PlusPower: Telling the VMMDev to close the VM ...\n"));
1481
1482 VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
1483 int vrc = VERR_NOT_IMPLEMENTED;
1484 if (pReq)
1485 {
1486 pReq->header.requestType = VMMDevReq_SetPowerStatus;
1487 pReq->powerState = VMMDevPowerState_PowerOff;
1488
1489 vrc = VbglR0GRPerform(&pReq->header);
1490 }
1491 if (RT_FAILURE(vrc))
1492 Log(("vgdrvNtNt5PlusPower: Error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
1493
1494 /* No need to do cleanup here; at this point we should've been
1495 * turned off by VMMDev already! */
1496 }
1497 break;
1498 }
1499
1500 case PowerActionHibernate:
1501 Log(("vgdrvNtNt5PlusPower: Power action hibernate!\n"));
1502 break;
1503
1504 case PowerActionWarmEject:
1505 Log(("vgdrvNtNt5PlusPower: PowerActionWarmEject!\n"));
1506 break;
1507
1508 default:
1509 Log(("vgdrvNtNt5PlusPower: %d\n", enmPowerAction));
1510 break;
1511 }
1512
1513 /*
1514 * Save the current system power action for later use.
1515 * This becomes handy when we return from hibernation for example.
1516 */
1517 if (pDevExt)
1518 pDevExt->enmLastSystemPowerAction = enmPowerAction;
1519
1520 break;
1521 }
1522 default:
1523 break;
1524 }
1525 break;
1526 }
1527 default:
1528 break;
1529 }
1530
1531 /*
1532 * Whether we are completing or relaying this power IRP,
1533 * we must call PoStartNextPowerIrp.
1534 */
1535 g_pfnPoStartNextPowerIrp(pIrp);
1536
1537 /*
1538 * Send the IRP down the driver stack, using PoCallDriver
1539 * (not IoCallDriver, as for non-power irps).
1540 */
1541 IoCopyCurrentIrpStackLocationToNext(pIrp);
1542 IoSetCompletionRoutine(pIrp,
1543 vgdrvNtNt5PlusPowerComplete,
1544 (PVOID)pDevExt,
1545 TRUE,
1546 TRUE,
1547 TRUE);
1548 return g_pfnPoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1549}
1550
1551
1552/**
1553 * IRP_MJ_SYSTEM_CONTROL handler.
1554 *
1555 * @returns NT status code
1556 * @param pDevObj Device object.
1557 * @param pIrp IRP.
1558 */
1559static NTSTATUS vgdrvNtNt5PlusSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1560{
1561 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1562
1563 LogFlowFuncEnter();
1564
1565 /* Always pass it on to the next driver. */
1566 IoSkipCurrentIrpStackLocation(pIrp);
1567
1568 return IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1569}
1570
1571
1572
1573/**
1574 * Unmaps the VMMDev I/O range from kernel space.
1575 *
1576 * @param pDevExt The device extension.
1577 */
1578static void vgdrvNtUnmapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt)
1579{
1580 LogFlowFunc(("pVMMDevMemory = %#x\n", pDevExt->Core.pVMMDevMemory));
1581 if (pDevExt->Core.pVMMDevMemory)
1582 {
1583 MmUnmapIoSpace((void*)pDevExt->Core.pVMMDevMemory, pDevExt->cbVmmDevMemory);
1584 pDevExt->Core.pVMMDevMemory = NULL;
1585 }
1586
1587 pDevExt->uVmmDevMemoryPhysAddr.QuadPart = 0;
1588 pDevExt->cbVmmDevMemory = 0;
1589}
1590
1591
1592/**
1593 * Unload the driver.
1594 *
1595 * @param pDrvObj Driver object.
1596 */
1597static void vgdrvNtUnload(PDRIVER_OBJECT pDrvObj)
1598{
1599 LogFlowFuncEnter();
1600
1601#ifdef TARGET_NT4
1602 /*
1603 * We need to destroy the device object here on NT4 and earlier.
1604 */
1605 PDEVICE_OBJECT pDevObj = pDrvObj->DeviceObject;
1606 if (pDevObj)
1607 {
1608 if (g_enmVGDrvNtVer <= VGDRVNTVER_WINNT4)
1609 {
1610 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1611 AssertPtr(pDevExt);
1612 AssertMsg(pDevExt->Core.uInitState == VBOXGUESTDEVEXT_INIT_STATE_RESOURCES,
1613 ("uInitState=%#x\n", pDevExt->Core.uInitState));
1614
1615 vgdrvNtDeleteDeviceResources(pDevExt);
1616 vgdrvNtDeleteDeviceFundamentAndUnlink(pDevObj, pDevExt);
1617 }
1618 }
1619#else /* !TARGET_NT4 */
1620 /*
1621 * On a PnP driver this routine will be called after IRP_MN_REMOVE_DEVICE
1622 * where we already did the cleanup, so don't do anything here (yet).
1623 */
1624 RT_NOREF1(pDrvObj);
1625#endif /* !TARGET_NT4 */
1626
1627 VGDrvCommonDestroyLoggers();
1628 RTR0Term();
1629
1630 /*
1631 * Finally deregister the bugcheck callback. Do it late to catch trouble in RTR0Term.
1632 */
1633 if (g_fBugCheckCallbackRegistered)
1634 {
1635 g_pfnKeDeregisterBugCheckCallback(&g_BugCheckCallbackRec);
1636 g_fBugCheckCallbackRegistered = false;
1637 }
1638}
1639
1640
1641/**
1642 * For simplifying request completion into a simple return statement, extended
1643 * version.
1644 *
1645 * @returns rcNt
1646 * @param rcNt The status code.
1647 * @param uInfo Extra info value.
1648 * @param pIrp The IRP.
1649 */
1650DECLINLINE(NTSTATUS) vgdrvNtCompleteRequestEx(NTSTATUS rcNt, ULONG_PTR uInfo, PIRP pIrp)
1651{
1652 pIrp->IoStatus.Status = rcNt;
1653 pIrp->IoStatus.Information = uInfo;
1654 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1655 return rcNt;
1656}
1657
1658
1659/**
1660 * For simplifying request completion into a simple return statement.
1661 *
1662 * @returns rcNt
1663 * @param rcNt The status code.
1664 * @param pIrp The IRP.
1665 */
1666DECLINLINE(NTSTATUS) vgdrvNtCompleteRequest(NTSTATUS rcNt, PIRP pIrp)
1667{
1668 return vgdrvNtCompleteRequestEx(rcNt, 0 /*uInfo*/, pIrp);
1669}
1670
1671
1672/**
1673 * Create (i.e. Open) file entry point.
1674 *
1675 * @param pDevObj Device object.
1676 * @param pIrp Request packet.
1677 */
1678static NTSTATUS vgdrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1679{
1680 Log(("vgdrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
1681 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1682 PFILE_OBJECT pFileObj = pStack->FileObject;
1683 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1684
1685 Assert(pFileObj->FsContext == NULL);
1686
1687 /*
1688 * We are not remotely similar to a directory...
1689 * (But this is possible.)
1690 */
1691 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
1692 {
1693 LogFlow(("vgdrvNtCreate: Failed. FILE_DIRECTORY_FILE set\n"));
1694 return vgdrvNtCompleteRequest(STATUS_NOT_A_DIRECTORY, pIrp);
1695 }
1696
1697 /*
1698 * Check the device state.
1699 */
1700 if (pDevExt->enmDevState != VGDRVNTDEVSTATE_WORKING)
1701 {
1702 LogFlow(("vgdrvNtCreate: Failed. Device is not in 'working' state: %d\n", pDevExt->enmDevState));
1703 return vgdrvNtCompleteRequest(STATUS_DEVICE_NOT_READY, pIrp);
1704 }
1705
1706 /*
1707 * Create a client session.
1708 */
1709 int rc;
1710 PVBOXGUESTSESSION pSession;
1711 if (pIrp->RequestorMode == KernelMode)
1712 rc = VGDrvCommonCreateKernelSession(&pDevExt->Core, &pSession);
1713 else
1714 rc = VGDrvCommonCreateUserSession(&pDevExt->Core, &pSession);
1715 if (RT_SUCCESS(rc))
1716 {
1717 pFileObj->FsContext = pSession;
1718 Log(("vgdrvNtCreate: Successfully created %s session %p\n",
1719 pIrp->RequestorMode == KernelMode ? "kernel" : "user", pSession));
1720 return vgdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
1721 }
1722
1723 Log(("vgdrvNtCreate: Failed to create session: rc=%Rrc\n", rc));
1724 /* Note. the IoStatus is completely ignored on error. */
1725 if (rc == VERR_NO_MEMORY)
1726 return vgdrvNtCompleteRequest(STATUS_NO_MEMORY, pIrp);
1727 return vgdrvNtCompleteRequest(STATUS_UNSUCCESSFUL, pIrp);
1728}
1729
1730
1731/**
1732 * Close file entry point.
1733 *
1734 * @param pDevObj Device object.
1735 * @param pIrp Request packet.
1736 */
1737static NTSTATUS vgdrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1738{
1739 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1740 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1741 PFILE_OBJECT pFileObj = pStack->FileObject;
1742
1743 LogFlowFunc(("pDevExt=0x%p, pFileObj=0x%p, FsContext=0x%p\n", pDevExt, pFileObj, pFileObj->FsContext));
1744
1745#ifdef VBOX_WITH_HGCM
1746 /* Close both, R0 and R3 sessions. */
1747 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFileObj->FsContext;
1748 if (pSession)
1749 VGDrvCommonCloseSession(&pDevExt->Core, pSession);
1750#endif
1751
1752 pFileObj->FsContext = NULL;
1753 pIrp->IoStatus.Information = 0;
1754 pIrp->IoStatus.Status = STATUS_SUCCESS;
1755 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1756
1757 return STATUS_SUCCESS;
1758}
1759
1760
1761/**
1762 * Device I/O Control entry point.
1763 *
1764 * @param pDevObj Device object.
1765 * @param pIrp Request packet.
1766 */
1767NTSTATUS _stdcall vgdrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1768{
1769 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1770 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1771 PVBOXGUESTSESSION pSession = pStack->FileObject ? (PVBOXGUESTSESSION)pStack->FileObject->FsContext : NULL;
1772
1773 if (!RT_VALID_PTR(pSession))
1774 return vgdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1775
1776#if 0 /* No fast I/O controls defined yet. */
1777 /*
1778 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1779 * the session and iCmd, and does not return anything.
1780 */
1781 if (pSession->fUnrestricted)
1782 {
1783 ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
1784 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
1785 || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
1786 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
1787 {
1788 int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
1789
1790 /* Complete the I/O request. */
1791 supdrvSessionRelease(pSession);
1792 return vgdrvNtCompleteRequest(RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER, pIrp);
1793 }
1794 }
1795#endif
1796
1797 return vgdrvNtDeviceControlSlow(&pDevExt->Core, pSession, pIrp, pStack);
1798}
1799
1800
1801/**
1802 * Device I/O Control entry point.
1803 *
1804 * @param pDevExt The device extension.
1805 * @param pSession The session.
1806 * @param pIrp Request packet.
1807 * @param pStack The request stack pointer.
1808 */
1809static NTSTATUS vgdrvNtDeviceControlSlow(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
1810 PIRP pIrp, PIO_STACK_LOCATION pStack)
1811{
1812 NTSTATUS rcNt;
1813 uint32_t cbOut = 0;
1814 int rc = 0;
1815 Log2(("vgdrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1816 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1817 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1818 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1819
1820#if 0 /*def RT_ARCH_AMD64*/
1821 /* Don't allow 32-bit processes to do any I/O controls. */
1822 if (!IoIs32bitProcess(pIrp))
1823#endif
1824 {
1825 /* Verify that it's a buffered CTL. */
1826 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1827 {
1828 /* Verify that the sizes in the request header are correct. */
1829 PVBGLREQHDR pHdr = (PVBGLREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1830 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1831 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
1832 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
1833 {
1834 /* Zero extra output bytes to make sure we don't leak anything. */
1835 if (pHdr->cbIn < pHdr->cbOut)
1836 RtlZeroMemory((uint8_t *)pHdr + pHdr->cbIn, pHdr->cbOut - pHdr->cbIn);
1837
1838 /*
1839 * Do the job.
1840 */
1841 rc = VGDrvCommonIoCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr,
1842 RT_MAX(pHdr->cbIn, pHdr->cbOut));
1843 if (RT_SUCCESS(rc))
1844 {
1845 rcNt = STATUS_SUCCESS;
1846 cbOut = pHdr->cbOut;
1847 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
1848 {
1849 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1850 LogRel(("vgdrvNtDeviceControlSlow: too much output! %#x > %#x; uCmd=%#x!\n",
1851 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
1852 }
1853
1854 /* If IDC successful disconnect request, we must set the context pointer to NULL. */
1855 if ( pStack->Parameters.DeviceIoControl.IoControlCode == VBGL_IOCTL_IDC_DISCONNECT
1856 && RT_SUCCESS(pHdr->rc))
1857 pStack->FileObject->FsContext = NULL;
1858 }
1859 else if (rc == VERR_NOT_SUPPORTED)
1860 rcNt = STATUS_NOT_SUPPORTED;
1861 else
1862 rcNt = STATUS_INVALID_PARAMETER;
1863 Log2(("vgdrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1864 }
1865 else
1866 {
1867 Log(("vgdrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1868 pStack->Parameters.DeviceIoControl.IoControlCode,
1869 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
1870 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
1871 pStack->Parameters.DeviceIoControl.InputBufferLength,
1872 pStack->Parameters.DeviceIoControl.OutputBufferLength));
1873 rcNt = STATUS_INVALID_PARAMETER;
1874 }
1875 }
1876 else
1877 {
1878 Log(("vgdrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
1879 pStack->Parameters.DeviceIoControl.IoControlCode));
1880 rcNt = STATUS_NOT_SUPPORTED;
1881 }
1882 }
1883#if 0 /*def RT_ARCH_AMD64*/
1884 else
1885 {
1886 Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
1887 rcNt = STATUS_NOT_SUPPORTED;
1888 }
1889#endif
1890
1891 return vgdrvNtCompleteRequestEx(rcNt, cbOut, pIrp);
1892}
1893
1894
1895/**
1896 * Internal Device I/O Control entry point (for IDC).
1897 *
1898 * @param pDevObj Device object.
1899 * @param pIrp Request packet.
1900 */
1901static NTSTATUS vgdrvNtInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1902{
1903 /* Currently no special code here. */
1904 return vgdrvNtDeviceControl(pDevObj, pIrp);
1905}
1906
1907
1908/**
1909 * IRP_MJ_SHUTDOWN handler.
1910 *
1911 * @returns NT status code
1912 * @param pDevObj Device object.
1913 * @param pIrp IRP.
1914 */
1915static NTSTATUS vgdrvNtShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1916{
1917 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1918 LogFlowFuncEnter();
1919
1920 VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
1921 if (pReq)
1922 {
1923 pReq->header.requestType = VMMDevReq_SetPowerStatus;
1924 pReq->powerState = VMMDevPowerState_PowerOff;
1925
1926 int rc = VbglR0GRPerform(&pReq->header);
1927 if (RT_FAILURE(rc))
1928 LogFunc(("Error performing request to VMMDev, rc=%Rrc\n", rc));
1929 }
1930
1931 /* just in case, since we shouldn't normally get here. */
1932 pIrp->IoStatus.Information = 0;
1933 pIrp->IoStatus.Status = STATUS_SUCCESS;
1934 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1935 return STATUS_SUCCESS;
1936}
1937
1938
1939/**
1940 * Stub function for functions we don't implemented.
1941 *
1942 * @returns STATUS_NOT_SUPPORTED
1943 * @param pDevObj Device object.
1944 * @param pIrp IRP.
1945 */
1946static NTSTATUS vgdrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1947{
1948 RT_NOREF1(pDevObj);
1949 LogFlowFuncEnter();
1950
1951 pIrp->IoStatus.Information = 0;
1952 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1953 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1954
1955 return STATUS_NOT_SUPPORTED;
1956}
1957
1958
1959/**
1960 * Bug check callback (KBUGCHECK_CALLBACK_ROUTINE).
1961 *
1962 * This adds a log entry on the host, in case Hyper-V isn't active or the guest
1963 * is too old for reporting it itself via the crash MSRs.
1964 *
1965 * @param pvBuffer Not used.
1966 * @param cbBuffer Not used.
1967 */
1968static VOID NTAPI vgdrvNtBugCheckCallback(PVOID pvBuffer, ULONG cbBuffer)
1969{
1970 if (g_pauKiBugCheckData)
1971 RTLogBackdoorPrintf("VBoxGuest: BugCheck! P0=%#zx P1=%#zx P2=%#zx P3=%#zx P4=%#zx\n", g_pauKiBugCheckData[0],
1972 g_pauKiBugCheckData[1], g_pauKiBugCheckData[2], g_pauKiBugCheckData[3], g_pauKiBugCheckData[4]);
1973 else
1974 RTLogBackdoorPrintf("VBoxGuest: BugCheck!\n");
1975
1976 RT_NOREF(pvBuffer, cbBuffer);
1977}
1978
1979
1980/**
1981 * Sets the mouse notification callback.
1982 *
1983 * @returns VBox status code.
1984 * @param pDevExt Pointer to the device extension.
1985 * @param pNotify Pointer to the mouse notify struct.
1986 */
1987int VGDrvNativeSetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, PVBGLIOCSETMOUSENOTIFYCALLBACK pNotify)
1988{
1989 PVBOXGUESTDEVEXTWIN pDevExtWin = (PVBOXGUESTDEVEXTWIN)pDevExt;
1990 /* we need a lock here to avoid concurrency with the set event functionality */
1991 KIRQL OldIrql;
1992 KeAcquireSpinLock(&pDevExtWin->MouseEventAccessSpinLock, &OldIrql);
1993 pDevExtWin->Core.pfnMouseNotifyCallback = pNotify->u.In.pfnNotify;
1994 pDevExtWin->Core.pvMouseNotifyCallbackArg = pNotify->u.In.pvUser;
1995 KeReleaseSpinLock(&pDevExtWin->MouseEventAccessSpinLock, OldIrql);
1996 return VINF_SUCCESS;
1997}
1998
1999
2000/**
2001 * DPC handler.
2002 *
2003 * @param pDPC DPC descriptor.
2004 * @param pDevObj Device object.
2005 * @param pIrp Interrupt request packet.
2006 * @param pContext Context specific pointer.
2007 */
2008static void NTAPI vgdrvNtDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext)
2009{
2010 RT_NOREF3(pDPC, pIrp, pContext);
2011 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2012 Log3Func(("pDevExt=0x%p\n", pDevExt));
2013
2014 /* Test & reset the counter. */
2015 if (ASMAtomicXchgU32(&pDevExt->Core.u32MousePosChangedSeq, 0))
2016 {
2017 /* we need a lock here to avoid concurrency with the set event ioctl handler thread,
2018 * i.e. to prevent the event from destroyed while we're using it */
2019 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
2020 KeAcquireSpinLockAtDpcLevel(&pDevExt->MouseEventAccessSpinLock);
2021
2022 if (pDevExt->Core.pfnMouseNotifyCallback)
2023 pDevExt->Core.pfnMouseNotifyCallback(pDevExt->Core.pvMouseNotifyCallbackArg);
2024
2025 KeReleaseSpinLockFromDpcLevel(&pDevExt->MouseEventAccessSpinLock);
2026 }
2027
2028 /* Process the wake-up list we were asked by the scheduling a DPC
2029 * in vgdrvNtIsrHandler(). */
2030 VGDrvCommonWaitDoWakeUps(&pDevExt->Core);
2031}
2032
2033
2034/**
2035 * ISR handler.
2036 *
2037 * @return BOOLEAN Indicates whether the IRQ came from us (TRUE) or not (FALSE).
2038 * @param pInterrupt Interrupt that was triggered.
2039 * @param pServiceContext Context specific pointer.
2040 */
2041static BOOLEAN NTAPI vgdrvNtIsrHandler(PKINTERRUPT pInterrupt, PVOID pServiceContext)
2042{
2043 RT_NOREF1(pInterrupt);
2044 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pServiceContext;
2045 if (pDevExt == NULL)
2046 return FALSE;
2047
2048 /*Log3Func(("pDevExt=0x%p, pVMMDevMemory=0x%p\n", pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL));*/
2049
2050 /* Enter the common ISR routine and do the actual work. */
2051 BOOLEAN fIRQTaken = VGDrvCommonISR(&pDevExt->Core);
2052
2053 /* If we need to wake up some events we do that in a DPC to make
2054 * sure we're called at the right IRQL. */
2055 if (fIRQTaken)
2056 {
2057 Log3Func(("IRQ was taken! pInterrupt=0x%p, pDevExt=0x%p\n", pInterrupt, pDevExt));
2058 if (ASMAtomicUoReadU32( &pDevExt->Core.u32MousePosChangedSeq)
2059 || !RTListIsEmpty(&pDevExt->Core.WakeUpList))
2060 {
2061 Log3Func(("Requesting DPC...\n"));
2062 IoRequestDpc(pDevExt->pDeviceObject, NULL /*pIrp*/, NULL /*pvContext*/);
2063 }
2064 }
2065 return fIRQTaken;
2066}
2067
2068
2069/**
2070 * Overridden routine for mouse polling events.
2071 *
2072 * @param pDevExt Device extension structure.
2073 */
2074void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
2075{
2076 NOREF(pDevExt);
2077 /* nothing to do here - i.e. since we can not KeSetEvent from ISR level,
2078 * we rely on the pDevExt->u32MousePosChangedSeq to be set to a non-zero value on a mouse event
2079 * and queue the DPC in our ISR routine in that case doing KeSetEvent from the DPC routine */
2080}
2081
2082
2083/**
2084 * Hook for handling OS specfic options from the host.
2085 *
2086 * @returns true if handled, false if not.
2087 * @param pDevExt The device extension.
2088 * @param pszName The option name.
2089 * @param pszValue The option value.
2090 */
2091bool VGDrvNativeProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue)
2092{
2093 RT_NOREF(pDevExt); RT_NOREF(pszName); RT_NOREF(pszValue);
2094 return false;
2095}
2096
2097
2098/**
2099 * Implements RTL_QUERY_REGISTRY_ROUTINE for enumerating our registry key.
2100 */
2101static NTSTATUS NTAPI vbdrvNtRegistryEnumCallback(PWSTR pwszValueName, ULONG uValueType,
2102 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
2103{
2104 /*
2105 * Filter out general service config values.
2106 */
2107 if ( RTUtf16ICmpAscii(pwszValueName, "Type") == 0
2108 || RTUtf16ICmpAscii(pwszValueName, "Start") == 0
2109 || RTUtf16ICmpAscii(pwszValueName, "ErrorControl") == 0
2110 || RTUtf16ICmpAscii(pwszValueName, "Tag") == 0
2111 || RTUtf16ICmpAscii(pwszValueName, "ImagePath") == 0
2112 || RTUtf16ICmpAscii(pwszValueName, "DisplayName") == 0
2113 || RTUtf16ICmpAscii(pwszValueName, "Group") == 0
2114 || RTUtf16ICmpAscii(pwszValueName, "DependOnGroup") == 0
2115 || RTUtf16ICmpAscii(pwszValueName, "DependOnService") == 0
2116 )
2117 {
2118 return STATUS_SUCCESS;
2119 }
2120
2121 /*
2122 * Convert the value name.
2123 */
2124 size_t cch = RTUtf16CalcUtf8Len(pwszValueName);
2125 if (cch < 64 && cch > 0)
2126 {
2127 char szValueName[72];
2128 char *pszTmp = szValueName;
2129 int rc = RTUtf16ToUtf8Ex(pwszValueName, RTSTR_MAX, &pszTmp, sizeof(szValueName), NULL);
2130 if (RT_SUCCESS(rc))
2131 {
2132 /*
2133 * Convert the value.
2134 */
2135 char szValue[72];
2136 char *pszFree = NULL;
2137 char *pszValue = NULL;
2138 szValue[0] = '\0';
2139 switch (uValueType)
2140 {
2141 case REG_SZ:
2142 case REG_EXPAND_SZ:
2143 rc = RTUtf16CalcUtf8LenEx((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &cch);
2144 if (RT_SUCCESS(rc) && cch < _1K)
2145 {
2146 if (cch < sizeof(szValue))
2147 {
2148 pszValue = szValue;
2149 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &pszValue, sizeof(szValue), NULL);
2150 }
2151 else
2152 {
2153 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &pszValue, sizeof(szValue), NULL);
2154 if (RT_SUCCESS(rc))
2155 pszFree = pszValue;
2156 }
2157 if (RT_FAILURE(rc))
2158 {
2159 LogRel(("VBoxGuest: Failed to convert registry value '%ls' string data to UTF-8: %Rrc\n",
2160 pwszValueName, rc));
2161 pszValue = NULL;
2162 }
2163 }
2164 else if (RT_SUCCESS(rc))
2165 LogRel(("VBoxGuest: Registry value '%ls' has a too long value: %#x (uvalueType=%#x)\n",
2166 pwszValueName, cbValue, uValueType));
2167 else
2168 LogRel(("VBoxGuest: Registry value '%ls' has an invalid string value (cbValue=%#x, uvalueType=%#x)\n",
2169 pwszValueName, cbValue, uValueType));
2170 break;
2171
2172 case REG_DWORD:
2173 if (cbValue == sizeof(uint32_t))
2174 {
2175 RTStrFormatU32(szValue, sizeof(szValue), *(uint32_t const *)pvValue, 10, 0, 0, 0);
2176 pszValue = szValue;
2177 }
2178 else
2179 LogRel(("VBoxGuest: Registry value '%ls' has wrong length for REG_DWORD: %#x\n", pwszValueName, cbValue));
2180 break;
2181
2182 case REG_QWORD:
2183 if (cbValue == sizeof(uint64_t))
2184 {
2185 RTStrFormatU32(szValue, sizeof(szValue), *(uint32_t const *)pvValue, 10, 0, 0, 0);
2186 pszValue = szValue;
2187 }
2188 else
2189 LogRel(("VBoxGuest: Registry value '%ls' has wrong length for REG_DWORD: %#x\n", pwszValueName, cbValue));
2190 break;
2191
2192 default:
2193 LogRel(("VBoxGuest: Ignoring registry value '%ls': Unsupported type %#x\n", pwszValueName, uValueType));
2194 break;
2195 }
2196 if (pszValue)
2197 {
2198 /*
2199 * Process it.
2200 */
2201 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
2202 VGDrvCommonProcessOption(pDevExt, szValueName, pszValue);
2203 if (pszFree)
2204 RTStrFree(pszFree);
2205 }
2206 }
2207 }
2208 else if (cch > 0)
2209 LogRel(("VBoxGuest: Ignoring registery value '%ls': name too long\n", pwszValueName));
2210 else
2211 LogRel(("VBoxGuest: Ignoring registery value with bad name\n", pwszValueName));
2212 NOREF(pvEntryCtx);
2213 return STATUS_SUCCESS;
2214}
2215
2216
2217/**
2218 * Reads configuration from the registry and guest properties.
2219 *
2220 * We ignore failures and instead preserve existing configuration values.
2221 *
2222 * Thie routine will block.
2223 *
2224 * @param pDevExt The device extension.
2225 */
2226static void vgdrvNtReadConfiguration(PVBOXGUESTDEVEXTWIN pDevExt)
2227{
2228 /*
2229 * First the registry.
2230 */
2231 RTL_QUERY_REGISTRY_TABLE aQuery[2];
2232 RT_ZERO(aQuery);
2233 aQuery[0].QueryRoutine = vbdrvNtRegistryEnumCallback;
2234 aQuery[0].Flags = 0;
2235 aQuery[0].Name = NULL;
2236 aQuery[0].EntryContext = NULL;
2237 aQuery[0].DefaultType = REG_NONE;
2238 NTSTATUS rcNt = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, L"VBoxGuest", &aQuery[0], pDevExt, NULL /* Environment */);
2239 if (!NT_SUCCESS(rcNt))
2240 LogRel(("VBoxGuest: RtlQueryRegistryValues failed: %#x\n", rcNt));
2241
2242 /*
2243 * Read configuration from the host.
2244 */
2245 VGDrvCommonProcessOptionsFromHost(&pDevExt->Core);
2246}
2247
2248
2249/**
2250 * Helper to scan the PCI resource list and remember stuff.
2251 *
2252 * @param pDevExt The device extension.
2253 * @param pResList Resource list
2254 * @param fTranslated Whether the addresses are translated or not.
2255 */
2256static NTSTATUS vgdrvNtScanPCIResourceList(PVBOXGUESTDEVEXTWIN pDevExt, PCM_RESOURCE_LIST pResList, bool fTranslated)
2257{
2258 /* Enumerate the resource list. */
2259 LogFlowFunc(("Found %d resources\n",
2260 pResList->List->PartialResourceList.Count));
2261
2262 NTSTATUS rc = STATUS_SUCCESS;
2263 PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialData = NULL;
2264 PVBOXGUESTWINBASEADDRESS pBaseAddress = pDevExt->aPciBaseAddresses;
2265 uint32_t cBaseAddresses = 0;
2266 bool fGotIrq = false;
2267 bool fGotMmio = false;
2268 bool fGotIoPorts = false;
2269 for (ULONG i = 0; i < pResList->List->PartialResourceList.Count; i++)
2270 {
2271 pPartialData = &pResList->List->PartialResourceList.PartialDescriptors[i];
2272 switch (pPartialData->Type)
2273 {
2274 case CmResourceTypePort:
2275 {
2276 LogFlowFunc(("I/O range: Base=%#RX64, length=%08x\n",
2277 pPartialData->u.Port.Start.QuadPart, pPartialData->u.Port.Length));
2278
2279 /* Overflow protection. */
2280 if (cBaseAddresses < PCI_TYPE0_ADDRESSES)
2281 {
2282 /* Save the first I/O port base. */
2283 if (!fGotIoPorts)
2284 {
2285 pDevExt->Core.IOPortBase = (RTIOPORT)pPartialData->u.Port.Start.LowPart;
2286 fGotIoPorts = true;
2287 }
2288 else
2289 LogRelFunc(("More than one I/O port range?!?\n"));
2290
2291 /* Save resource information. */
2292 pBaseAddress->RangeStart = pPartialData->u.Port.Start;
2293 pBaseAddress->RangeLength = pPartialData->u.Port.Length;
2294 pBaseAddress->RangeInMemory = FALSE;
2295 pBaseAddress->ResourceMapped = FALSE;
2296
2297 LogFunc(("I/O range for VMMDev found! Base=%#RX64, length=%08x\n",
2298 pPartialData->u.Port.Start.QuadPart, pPartialData->u.Port.Length));
2299
2300 /* Next item ... */
2301 pBaseAddress++;
2302 cBaseAddresses++;
2303 }
2304 else
2305 LogFunc(("Too many PCI addresses!\n"));
2306 break;
2307 }
2308
2309 case CmResourceTypeInterrupt:
2310 {
2311 LogFunc(("Interrupt: Level=%x, vector=%x, mode=%x\n",
2312 pPartialData->u.Interrupt.Level, pPartialData->u.Interrupt.Vector, pPartialData->Flags));
2313
2314 if (!fGotIrq)
2315 {
2316 /* Save information. */
2317 pDevExt->uInterruptLevel = pPartialData->u.Interrupt.Level;
2318 pDevExt->uInterruptVector = pPartialData->u.Interrupt.Vector;
2319 pDevExt->fInterruptAffinity = pPartialData->u.Interrupt.Affinity;
2320
2321 /* Check interrupt mode. */
2322 if (pPartialData->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
2323 pDevExt->enmInterruptMode = Latched;
2324 else
2325 pDevExt->enmInterruptMode = LevelSensitive;
2326 fGotIrq = true;
2327 }
2328 else
2329 LogFunc(("More than one IRQ resource!\n"));
2330 break;
2331 }
2332
2333 case CmResourceTypeMemory:
2334 {
2335 LogFlowFunc(("Memory range: Base=%#RX64, length=%08x\n",
2336 pPartialData->u.Memory.Start.QuadPart, pPartialData->u.Memory.Length));
2337
2338 /* Overflow protection. */
2339 if (cBaseAddresses < PCI_TYPE0_ADDRESSES)
2340 {
2341 /* We only care about the first read/write memory range. */
2342 if ( !fGotMmio
2343 && (pPartialData->Flags & CM_RESOURCE_MEMORY_WRITEABILITY_MASK) == CM_RESOURCE_MEMORY_READ_WRITE)
2344 {
2345 /* Save physical MMIO base + length for VMMDev. */
2346 pDevExt->uVmmDevMemoryPhysAddr = pPartialData->u.Memory.Start;
2347 pDevExt->cbVmmDevMemory = (ULONG)pPartialData->u.Memory.Length;
2348
2349 if (!fTranslated)
2350 {
2351 /* Technically we need to make the HAL translate the address. since we
2352 didn't used to do this and it probably just returns the input address,
2353 we allow ourselves to ignore failures. */
2354 ULONG uAddressSpace = 0;
2355 PHYSICAL_ADDRESS PhysAddr = pPartialData->u.Memory.Start;
2356 if (HalTranslateBusAddress(pResList->List->InterfaceType, pResList->List->BusNumber, PhysAddr,
2357 &uAddressSpace, &PhysAddr))
2358 {
2359 Log(("HalTranslateBusAddress(%#RX64) -> %RX64, type %#x\n",
2360 pPartialData->u.Memory.Start.QuadPart, PhysAddr.QuadPart, uAddressSpace));
2361 if (pPartialData->u.Memory.Start.QuadPart != PhysAddr.QuadPart)
2362 pDevExt->uVmmDevMemoryPhysAddr = PhysAddr;
2363 }
2364 else
2365 Log(("HalTranslateBusAddress(%#RX64) -> failed!\n", pPartialData->u.Memory.Start.QuadPart));
2366 }
2367
2368 /* Save resource information. */
2369 pBaseAddress->RangeStart = pPartialData->u.Memory.Start;
2370 pBaseAddress->RangeLength = pPartialData->u.Memory.Length;
2371 pBaseAddress->RangeInMemory = TRUE;
2372 pBaseAddress->ResourceMapped = FALSE;
2373
2374 LogFunc(("Found memory range for VMMDev! Base = %#RX64, Length = %08x\n",
2375 pPartialData->u.Memory.Start.QuadPart, pPartialData->u.Memory.Length));
2376
2377 /* Next item ... */
2378 cBaseAddresses++;
2379 pBaseAddress++;
2380 fGotMmio = true;
2381 }
2382 else
2383 LogFunc(("Ignoring memory: Flags=%08x Base=%#RX64\n",
2384 pPartialData->Flags, pPartialData->u.Memory.Start.QuadPart));
2385 }
2386 else
2387 LogFunc(("Too many PCI addresses!\n"));
2388 break;
2389 }
2390
2391 default:
2392 {
2393 LogFunc(("Unhandled resource found, type=%d\n", pPartialData->Type));
2394 break;
2395 }
2396 }
2397 }
2398
2399 /* Memorize the number of resources found. */
2400 pDevExt->cPciAddresses = cBaseAddresses;
2401 return rc;
2402}
2403
2404
2405/**
2406 * Maps the I/O space from VMMDev to virtual kernel address space.
2407 *
2408 * @return NTSTATUS
2409 *
2410 * @param pDevExt The device extension.
2411 * @param PhysAddr Physical address to map.
2412 * @param cbToMap Number of bytes to map.
2413 * @param ppvMMIOBase Pointer of mapped I/O base.
2414 * @param pcbMMIO Length of mapped I/O base.
2415 */
2416static NTSTATUS vgdrvNtMapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS PhysAddr, ULONG cbToMap,
2417 void **ppvMMIOBase, uint32_t *pcbMMIO)
2418{
2419 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
2420 AssertPtrReturn(ppvMMIOBase, VERR_INVALID_POINTER);
2421 /* pcbMMIO is optional. */
2422
2423 NTSTATUS rc = STATUS_SUCCESS;
2424 if (PhysAddr.LowPart > 0) /* We're mapping below 4GB. */
2425 {
2426 VMMDevMemory *pVMMDevMemory = (VMMDevMemory *)MmMapIoSpace(PhysAddr, cbToMap, MmNonCached);
2427 LogFlowFunc(("pVMMDevMemory = %#x\n", pVMMDevMemory));
2428 if (pVMMDevMemory)
2429 {
2430 LogFunc(("VMMDevMemory: Version = %#x, Size = %d\n", pVMMDevMemory->u32Version, pVMMDevMemory->u32Size));
2431
2432 /* Check version of the structure; do we have the right memory version? */
2433 if (pVMMDevMemory->u32Version == VMMDEV_MEMORY_VERSION)
2434 {
2435 /* Save results. */
2436 *ppvMMIOBase = pVMMDevMemory;
2437 if (pcbMMIO) /* Optional. */
2438 *pcbMMIO = pVMMDevMemory->u32Size;
2439
2440 LogFlowFunc(("VMMDevMemory found and mapped! pvMMIOBase = 0x%p\n", *ppvMMIOBase));
2441 }
2442 else
2443 {
2444 /* Not our version, refuse operation and unmap the memory. */
2445 LogFunc(("Wrong version (%u), refusing operation!\n", pVMMDevMemory->u32Version));
2446
2447 vgdrvNtUnmapVMMDevMemory(pDevExt);
2448 rc = STATUS_UNSUCCESSFUL;
2449 }
2450 }
2451 else
2452 rc = STATUS_UNSUCCESSFUL;
2453 }
2454 return rc;
2455}
2456
2457#ifdef VBOX_STRICT
2458
2459/**
2460 * A quick implementation of AtomicTestAndClear for uint32_t and multiple bits.
2461 */
2462static uint32_t vgdrvNtAtomicBitsTestAndClear(void *pu32Bits, uint32_t u32Mask)
2463{
2464 AssertPtrReturn(pu32Bits, 0);
2465 LogFlowFunc(("*pu32Bits=%#x, u32Mask=%#x\n", *(uint32_t *)pu32Bits, u32Mask));
2466 uint32_t u32Result = 0;
2467 uint32_t u32WorkingMask = u32Mask;
2468 int iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
2469
2470 while (iBitOffset > 0)
2471 {
2472 bool fSet = ASMAtomicBitTestAndClear(pu32Bits, iBitOffset - 1);
2473 if (fSet)
2474 u32Result |= 1 << (iBitOffset - 1);
2475 u32WorkingMask &= ~(1 << (iBitOffset - 1));
2476 iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
2477 }
2478 LogFlowFunc(("Returning %#x\n", u32Result));
2479 return u32Result;
2480}
2481
2482
2483static void vgdrvNtTestAtomicTestAndClearBitsU32(uint32_t u32Mask, uint32_t u32Bits, uint32_t u32Exp)
2484{
2485 ULONG u32Bits2 = u32Bits;
2486 uint32_t u32Result = vgdrvNtAtomicBitsTestAndClear(&u32Bits2, u32Mask);
2487 if ( u32Result != u32Exp
2488 || (u32Bits2 & u32Mask)
2489 || (u32Bits2 & u32Result)
2490 || ((u32Bits2 | u32Result) != u32Bits)
2491 )
2492 AssertLogRelMsgFailed(("TEST FAILED: u32Mask=%#x, u32Bits (before)=%#x, u32Bits (after)=%#x, u32Result=%#x, u32Exp=%#x\n",
2493 u32Mask, u32Bits, u32Bits2, u32Result));
2494}
2495
2496
2497static void vgdrvNtDoTests(void)
2498{
2499 vgdrvNtTestAtomicTestAndClearBitsU32(0x00, 0x23, 0);
2500 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0, 0);
2501 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x22, 0);
2502 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x23, 0x1);
2503 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x32, 0x10);
2504 vgdrvNtTestAtomicTestAndClearBitsU32(0x22, 0x23, 0x22);
2505}
2506
2507#endif /* VBOX_STRICT */
2508
2509#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
2510
2511/*
2512 * DPC latency checker.
2513 */
2514
2515/**
2516 * One DPC latency sample.
2517 */
2518typedef struct DPCSAMPLE
2519{
2520 LARGE_INTEGER PerfDelta;
2521 LARGE_INTEGER PerfCounter;
2522 LARGE_INTEGER PerfFrequency;
2523 uint64_t u64TSC;
2524} DPCSAMPLE;
2525AssertCompileSize(DPCSAMPLE, 4*8);
2526
2527/**
2528 * The DPC latency measurement workset.
2529 */
2530typedef struct DPCDATA
2531{
2532 KDPC Dpc;
2533 KTIMER Timer;
2534 KSPIN_LOCK SpinLock;
2535
2536 ULONG ulTimerRes;
2537
2538 bool volatile fFinished;
2539
2540 /** The timer interval (relative). */
2541 LARGE_INTEGER DueTime;
2542
2543 LARGE_INTEGER PerfCounterPrev;
2544
2545 /** Align the sample array on a 64 byte boundrary just for the off chance
2546 * that we'll get cache line aligned memory backing this structure. */
2547 uint32_t auPadding[ARCH_BITS == 32 ? 5 : 7];
2548
2549 int cSamples;
2550 DPCSAMPLE aSamples[8192];
2551} DPCDATA;
2552
2553AssertCompileMemberAlignment(DPCDATA, aSamples, 64);
2554
2555# define VBOXGUEST_DPC_TAG 'DPCS'
2556
2557
2558/**
2559 * DPC callback routine for the DPC latency measurement code.
2560 *
2561 * @param pDpc The DPC, not used.
2562 * @param pvDeferredContext Pointer to the DPCDATA.
2563 * @param SystemArgument1 System use, ignored.
2564 * @param SystemArgument2 System use, ignored.
2565 */
2566static VOID vgdrvNtDpcLatencyCallback(PKDPC pDpc, PVOID pvDeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
2567{
2568 DPCDATA *pData = (DPCDATA *)pvDeferredContext;
2569 RT_NOREF(pDpc, SystemArgument1, SystemArgument2);
2570
2571 KeAcquireSpinLockAtDpcLevel(&pData->SpinLock);
2572
2573 if (pData->cSamples >= RT_ELEMENTS(pData->aSamples))
2574 pData->fFinished = true;
2575 else
2576 {
2577 DPCSAMPLE *pSample = &pData->aSamples[pData->cSamples++];
2578
2579 pSample->u64TSC = ASMReadTSC();
2580 pSample->PerfCounter = KeQueryPerformanceCounter(&pSample->PerfFrequency);
2581 pSample->PerfDelta.QuadPart = pSample->PerfCounter.QuadPart - pData->PerfCounterPrev.QuadPart;
2582
2583 pData->PerfCounterPrev.QuadPart = pSample->PerfCounter.QuadPart;
2584
2585 KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
2586 }
2587
2588 KeReleaseSpinLockFromDpcLevel(&pData->SpinLock);
2589}
2590
2591
2592/**
2593 * Handles the DPC latency checker request.
2594 *
2595 * @returns VBox status code.
2596 */
2597int VGDrvNtIOCtl_DpcLatencyChecker(void)
2598{
2599 /*
2600 * Allocate a block of non paged memory for samples and related data.
2601 */
2602 DPCDATA *pData = (DPCDATA *)RTMemAlloc(sizeof(DPCDATA));
2603 if (!pData)
2604 {
2605 RTLogBackdoorPrintf("VBoxGuest: DPC: DPCDATA allocation failed.\n");
2606 return VERR_NO_MEMORY;
2607 }
2608
2609 /*
2610 * Initialize the data.
2611 */
2612 KeInitializeDpc(&pData->Dpc, vgdrvNtDpcLatencyCallback, pData);
2613 KeInitializeTimer(&pData->Timer);
2614 KeInitializeSpinLock(&pData->SpinLock);
2615
2616 pData->fFinished = false;
2617 pData->cSamples = 0;
2618 pData->PerfCounterPrev.QuadPart = 0;
2619
2620 pData->ulTimerRes = ExSetTimerResolution(1000 * 10, 1);
2621 pData->DueTime.QuadPart = -(int64_t)pData->ulTimerRes / 10;
2622
2623 /*
2624 * Start the DPC measurements and wait for a full set.
2625 */
2626 KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
2627
2628 while (!pData->fFinished)
2629 {
2630 LARGE_INTEGER Interval;
2631 Interval.QuadPart = -100 * 1000 * 10;
2632 KeDelayExecutionThread(KernelMode, TRUE, &Interval);
2633 }
2634
2635 ExSetTimerResolution(0, 0);
2636
2637 /*
2638 * Log everything to the host.
2639 */
2640 RTLogBackdoorPrintf("DPC: ulTimerRes = %d\n", pData->ulTimerRes);
2641 for (int i = 0; i < pData->cSamples; i++)
2642 {
2643 DPCSAMPLE *pSample = &pData->aSamples[i];
2644
2645 RTLogBackdoorPrintf("[%d] pd %lld pc %lld pf %lld t %lld\n",
2646 i,
2647 pSample->PerfDelta.QuadPart,
2648 pSample->PerfCounter.QuadPart,
2649 pSample->PerfFrequency.QuadPart,
2650 pSample->u64TSC);
2651 }
2652
2653 RTMemFree(pData);
2654 return VINF_SUCCESS;
2655}
2656
2657#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
2658
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