VirtualBox

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

Last change on this file since 107032 was 106909, checked in by vboxsync, 3 months ago

Add/common/VBoxGuest: Save 8 bytes of padding. bugref:10734

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 136.9 KB
Line 
1/* $Id: VBoxGuest-win.cpp 106909 2024-11-09 01:48:03Z vboxsync $ */
2/** @file
3 * VBoxGuest - Windows specifics.
4 */
5
6/*
7 * Copyright (C) 2010-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP LOG_GROUP_SUP_DRV
42#include <iprt/nt/nt.h>
43
44#include "VBoxGuestInternal.h"
45#include <VBox/VBoxGuestLib.h>
46#include <VBox/log.h>
47
48#include <iprt/asm.h>
49#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
50# include <iprt/asm-amd64-x86.h>
51#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_X86)
52# include <iprt/asm-arm.h>
53#else
54# error "Port me"
55#endif
56#include <iprt/buildconfig.h>
57#include <iprt/critsect.h>
58#include <iprt/dbg.h>
59#include <iprt/err.h>
60#include <iprt/initterm.h>
61#include <iprt/memobj.h>
62#include <iprt/mem.h>
63#include <iprt/mp.h>
64#include <iprt/spinlock.h>
65#include <iprt/string.h>
66#include <iprt/utf16.h>
67
68#ifdef TARGET_NT4
69# include <VBox/pci.h>
70# define PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS32_IPRT
71# include <iprt/formats/mz.h>
72# include <iprt/formats/pecoff.h>
73extern "C" IMAGE_DOS_HEADER __ImageBase;
74#endif
75
76
77/*********************************************************************************************************************************
78* Defined Constants And Macros *
79*********************************************************************************************************************************/
80#undef ExFreePool
81
82#ifndef PCI_MAX_BUSES
83# define PCI_MAX_BUSES 256
84#endif
85
86/** CM_RESOURCE_MEMORY_* flags which were used on XP or earlier. */
87#define VBOX_CM_PRE_VISTA_MASK (0x3f)
88
89
90/*********************************************************************************************************************************
91* Structures and Typedefs *
92*********************************************************************************************************************************/
93/**
94 * Possible device states for our state machine.
95 */
96typedef enum VGDRVNTDEVSTATE
97{
98 /** @name Stable states
99 * @{ */
100 VGDRVNTDEVSTATE_REMOVED = 0,
101 VGDRVNTDEVSTATE_STOPPED,
102 VGDRVNTDEVSTATE_OPERATIONAL,
103 /** @} */
104
105 /** @name Transitional states
106 * @{ */
107 VGDRVNTDEVSTATE_PENDINGSTOP,
108 VGDRVNTDEVSTATE_PENDINGREMOVE,
109 VGDRVNTDEVSTATE_SURPRISEREMOVED
110 /** @} */
111} VGDRVNTDEVSTATE;
112
113
114/**
115 * Subclassing the device extension for adding windows-specific bits.
116 */
117typedef struct VBOXGUESTDEVEXTWIN
118{
119 /** The common device extension core. */
120 VBOXGUESTDEVEXT Core;
121
122 /** Our functional driver object. */
123 PDEVICE_OBJECT pDeviceObject;
124 /** Top of the stack. */
125 PDEVICE_OBJECT pNextLowerDriver;
126
127 /** @name PCI bus and slot (device+function) set by for legacy NT only.
128 * @{ */
129 /** Bus number where the device is located. */
130 ULONG uBus;
131 /** Slot number where the device is located (PCI_SLOT_NUMBER). */
132 ULONG uSlot;
133 /** @} */
134
135 /** @name Interrupt stuff.
136 * @{ */
137 /** Interrupt object pointer. */
138 PKINTERRUPT pInterruptObject;
139 /** Device interrupt level. */
140 ULONG uInterruptLevel;
141 /** Device interrupt vector. */
142 ULONG uInterruptVector;
143 /** Affinity mask. */
144 KAFFINITY fInterruptAffinity;
145 /** LevelSensitive or Latched. */
146 KINTERRUPT_MODE enmInterruptMode;
147 /** @} */
148
149 /** Physical address and length of VMMDev memory. */
150 PHYSICAL_ADDRESS uVmmDevMemoryPhysAddr;
151 /** Length of VMMDev memory. */
152 ULONG cbVmmDevMemory;
153
154 /** Length of the optional VMMDev MMIO request interface. */
155 ULONG cbMmioReq;
156 /** Physical address and length of the optional VMMDev MMIO request interface. */
157 PHYSICAL_ADDRESS GCPhysMmioReq;
158
159 /** Device state. */
160 VGDRVNTDEVSTATE volatile enmDevState;
161 /** The previous stable device state. */
162 VGDRVNTDEVSTATE enmPrevDevState;
163
164 /** Last system power action set (see VBoxGuestPower). */
165 POWER_ACTION enmLastSystemPowerAction;
166 /** Preallocated generic request for shutdown. */
167 VMMDevPowerStateRequest *pPowerStateRequest;
168
169 /** Spinlock protecting MouseNotifyCallback. Required since the consumer is
170 * in a DPC callback and not the ISR. */
171 KSPIN_LOCK MouseEventAccessSpinLock;
172
173 /** Read/write critical section for handling race between checking for idle
174 * driver (in IRP_MN_QUERY_REMOVE_DEVICE & IRP_MN_QUERY_STOP_DEVICE) and
175 * creating new sessions. The session creation code enteres the critical
176 * section in read (shared) access mode, whereas the idle checking code
177 * enteres is in write (exclusive) access mode. */
178 RTCRITSECTRW SessionCreateCritSect;
179} VBOXGUESTDEVEXTWIN;
180typedef VBOXGUESTDEVEXTWIN *PVBOXGUESTDEVEXTWIN;
181
182
183/** NT (windows) version identifier. */
184typedef enum VGDRVNTVER
185{
186 VGDRVNTVER_INVALID = 0,
187 VGDRVNTVER_WINNT310,
188 VGDRVNTVER_WINNT350,
189 VGDRVNTVER_WINNT351,
190 VGDRVNTVER_WINNT4,
191 VGDRVNTVER_WIN2K,
192 VGDRVNTVER_WINXP,
193 VGDRVNTVER_WIN2K3,
194 VGDRVNTVER_WINVISTA,
195 VGDRVNTVER_WIN7,
196 VGDRVNTVER_WIN8,
197 VGDRVNTVER_WIN81,
198 VGDRVNTVER_WIN10,
199 VGDRVNTVER_WIN11
200} VGDRVNTVER;
201
202
203/*********************************************************************************************************************************
204* Internal Functions *
205*********************************************************************************************************************************/
206RT_C_DECLS_BEGIN
207static NTSTATUS NTAPI vgdrvNtNt5PlusAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj);
208static NTSTATUS NTAPI vgdrvNtNt5PlusPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp);
209static NTSTATUS NTAPI vgdrvNtNt5PlusPower(PDEVICE_OBJECT pDevObj, PIRP pIrp);
210static NTSTATUS NTAPI vgdrvNtNt5PlusSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
211static void NTAPI vgdrvNtUnload(PDRIVER_OBJECT pDrvObj);
212static NTSTATUS NTAPI vgdrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
213static NTSTATUS NTAPI vgdrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
214static NTSTATUS NTAPI vgdrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
215static NTSTATUS vgdrvNtDeviceControlSlow(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
216 PIRP pIrp, PIO_STACK_LOCATION pStack);
217static NTSTATUS NTAPI vgdrvNtInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
218static void vgdrvNtReadConfiguration(PVBOXGUESTDEVEXTWIN pDevExt);
219static NTSTATUS NTAPI vgdrvNtShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp);
220static NTSTATUS NTAPI vgdrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
221static VOID NTAPI vgdrvNtBugCheckCallback(PVOID pvBuffer, ULONG cbBuffer);
222static VOID NTAPI vgdrvNtDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext);
223static BOOLEAN NTAPI vgdrvNtIsrHandler(PKINTERRUPT interrupt, PVOID serviceContext);
224#ifdef VBOX_STRICT
225static void vgdrvNtDoTests(void);
226#endif
227#ifdef TARGET_NT4
228static ULONG NTAPI vgdrvNt31GetBusDataByOffset(BUS_DATA_TYPE enmBusDataType, ULONG idxBus, ULONG uSlot,
229 void *pvData, ULONG offData, ULONG cbData);
230static ULONG NTAPI vgdrvNt31SetBusDataByOffset(BUS_DATA_TYPE enmBusDataType, ULONG idxBus, ULONG uSlot,
231 void *pvData, ULONG offData, ULONG cbData);
232#endif
233
234/*
235 * We only do INIT allocations. PAGE is too much work and risk for little gain.
236 */
237#ifdef ALLOC_PRAGMA
238NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
239# pragma alloc_text(INIT, DriverEntry)
240# ifdef TARGET_NT4
241static NTSTATUS vgdrvNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
242# pragma alloc_text(INIT, vgdrvNt4CreateDevice)
243static NTSTATUS vgdrvNt4FindPciDevice(PULONG puluBusNumber, PPCI_SLOT_NUMBER puSlotNumber);
244# pragma alloc_text(INIT, vgdrvNt4FindPciDevice)
245# endif
246#endif
247RT_C_DECLS_END
248
249
250/*********************************************************************************************************************************
251* Global Variables *
252*********************************************************************************************************************************/
253/** The detected NT (windows) version. */
254static VGDRVNTVER g_enmVGDrvNtVer = VGDRVNTVER_INVALID;
255/** Pointer to the PoStartNextPowerIrp routine (in the NT kernel).
256 * Introduced in Windows 2000. */
257static decltype(PoStartNextPowerIrp) *g_pfnPoStartNextPowerIrp = NULL;
258/** Pointer to the PoCallDriver routine (in the NT kernel).
259 * Introduced in Windows 2000. */
260static decltype(PoCallDriver) *g_pfnPoCallDriver = NULL;
261#ifdef TARGET_NT4
262/** Pointer to the HalAssignSlotResources routine (in the HAL).
263 * Introduced in NT 3.50. */
264static decltype(HalAssignSlotResources) *g_pfnHalAssignSlotResources= NULL;
265/** Pointer to the HalGetBusDataByOffset routine (in the HAL).
266 * Introduced in NT 3.50. */
267static decltype(HalGetBusDataByOffset) *g_pfnHalGetBusDataByOffset = NULL;
268/** Pointer to the HalSetBusDataByOffset routine (in the HAL).
269 * Introduced in NT 3.50 (we provide fallback and use it only for NT 3.1). */
270static decltype(HalSetBusDataByOffset) *g_pfnHalSetBusDataByOffset = NULL;
271#endif
272/** Pointer to the KeRegisterBugCheckCallback routine (in the NT kernel).
273 * Introduced in Windows 3.50. */
274static decltype(KeRegisterBugCheckCallback) *g_pfnKeRegisterBugCheckCallback = NULL;
275/** Pointer to the KeRegisterBugCheckCallback routine (in the NT kernel).
276 * Introduced in Windows 3.50. */
277static decltype(KeDeregisterBugCheckCallback) *g_pfnKeDeregisterBugCheckCallback = NULL;
278/** Pointer to the KiBugCheckData array (in the NT kernel).
279 * Introduced in Windows 4. */
280static uintptr_t const *g_pauKiBugCheckData = NULL;
281/** Set if the callback was successfully registered and needs deregistering. */
282static bool g_fBugCheckCallbackRegistered = false;
283/** The bugcheck callback record. */
284static KBUGCHECK_CALLBACK_RECORD g_BugCheckCallbackRec;
285
286
287
288/**
289 * Driver entry point.
290 *
291 * @returns appropriate status code.
292 * @param pDrvObj Pointer to driver object.
293 * @param pRegPath Registry base path.
294 */
295NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
296{
297 RT_NOREF1(pRegPath);
298#ifdef TARGET_NT4
299 /*
300 * Looks like NT 3.1 doesn't necessarily zero our uninitialized data segments
301 * (like ".bss"), at least not when loading at runtime, so do that.
302 */
303 PIMAGE_DOS_HEADER pMzHdr = &__ImageBase;
304 PIMAGE_NT_HEADERS32 pNtHdrs = (PIMAGE_NT_HEADERS32)((uint8_t *)pMzHdr + pMzHdr->e_lfanew);
305 if ( pNtHdrs->Signature == IMAGE_NT_SIGNATURE
306 && pNtHdrs->FileHeader.NumberOfSections > 2
307 && pNtHdrs->FileHeader.NumberOfSections < 64)
308 {
309 uint32_t iShdr = pNtHdrs->FileHeader.NumberOfSections;
310 uint32_t uRvaEnd = pNtHdrs->OptionalHeader.SizeOfImage; /* (may be changed to exclude tail sections) */
311 PIMAGE_SECTION_HEADER paShdrs;
312 paShdrs = (PIMAGE_SECTION_HEADER)&pNtHdrs->OptionalHeader.DataDirectory[pNtHdrs->OptionalHeader.NumberOfRvaAndSizes];
313 while (iShdr-- > 0)
314 {
315 if ( !(paShdrs[iShdr].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
316 && paShdrs[iShdr].VirtualAddress < uRvaEnd)
317 {
318 uint32_t const cbSection = uRvaEnd - paShdrs[iShdr].VirtualAddress;
319 uint32_t const offUninitialized = paShdrs[iShdr].SizeOfRawData;
320 //RTLogBackdoorPrintf("section #%u: rva=%#x size=%#x calcsize=%#x) rawsize=%#x\n", iShdr,
321 // paShdrs[iShdr].VirtualAddress, paShdrs[iShdr].Misc.VirtualSize, cbSection, offUninitialized);
322 if ( offUninitialized < cbSection
323 && (paShdrs[iShdr].Characteristics & IMAGE_SCN_MEM_WRITE))
324 memset((uint8_t *)pMzHdr + paShdrs[iShdr].VirtualAddress + offUninitialized, 0, cbSection - offUninitialized);
325 uRvaEnd = paShdrs[iShdr].VirtualAddress;
326 }
327 }
328 }
329 else
330 RTLogBackdoorPrintf("VBoxGuest: Bad pNtHdrs=%p: %#x\n", pNtHdrs, pNtHdrs->Signature);
331#endif
332
333 /*
334 * Start by initializing IPRT.
335 */
336 int rc = RTR0Init(0);
337 if (RT_FAILURE(rc))
338 {
339 RTLogBackdoorPrintf("VBoxGuest: RTR0Init failed: %Rrc!\n", rc);
340 return STATUS_UNSUCCESSFUL;
341 }
342 VGDrvCommonInitLoggers();
343
344 LogFunc(("Driver built: %s %s\n", __DATE__, __TIME__));
345
346 /*
347 * Check if the NT version is supported and initialize g_enmVGDrvNtVer.
348 */
349 ULONG ulMajorVer;
350 ULONG ulMinorVer;
351 ULONG ulBuildNo;
352 BOOLEAN fCheckedBuild = PsGetVersion(&ulMajorVer, &ulMinorVer, &ulBuildNo, NULL);
353
354 /* Use RTLogBackdoorPrintf to make sure that this goes to VBox.log on the host. */
355 RTLogBackdoorPrintf("VBoxGuest: %s r%s Windows version %u.%u, build %u%s\n",
356 RTBldCfgVersion(), RTBldCfgRevisionStr(), ulMajorVer, ulMinorVer, ulBuildNo,
357 fCheckedBuild ? ", checked build" : "");
358
359#ifdef VBOX_STRICT
360 vgdrvNtDoTests();
361#endif
362 NTSTATUS rcNt = STATUS_SUCCESS;
363 switch (ulMajorVer)
364 {
365 case 10:
366 /* Windows 10 Preview builds starting with 9926. */
367 g_enmVGDrvNtVer = VGDRVNTVER_WIN10;
368 /* Windows 11 Preview builds starting with 22000. */
369 if (ulBuildNo >= 22000)
370 g_enmVGDrvNtVer = VGDRVNTVER_WIN11;
371 break;
372 case 6: /* Windows Vista or Windows 7 (based on minor ver) */
373 switch (ulMinorVer)
374 {
375 case 0: /* Note: Also could be Windows 2008 Server! */
376 g_enmVGDrvNtVer = VGDRVNTVER_WINVISTA;
377 break;
378 case 1: /* Note: Also could be Windows 2008 Server R2! */
379 g_enmVGDrvNtVer = VGDRVNTVER_WIN7;
380 break;
381 case 2:
382 g_enmVGDrvNtVer = VGDRVNTVER_WIN8;
383 break;
384 case 3:
385 g_enmVGDrvNtVer = VGDRVNTVER_WIN81;
386 break;
387 case 4: /* Windows 10 Preview builds. */
388 default:
389 g_enmVGDrvNtVer = VGDRVNTVER_WIN10;
390 break;
391 }
392 break;
393 case 5:
394 switch (ulMinorVer)
395 {
396 default:
397 case 2:
398 g_enmVGDrvNtVer = VGDRVNTVER_WIN2K3;
399 break;
400 case 1:
401 g_enmVGDrvNtVer = VGDRVNTVER_WINXP;
402 break;
403 case 0:
404 g_enmVGDrvNtVer = VGDRVNTVER_WIN2K;
405 break;
406 }
407 break;
408 case 4:
409 g_enmVGDrvNtVer = VGDRVNTVER_WINNT4;
410 break;
411 case 3:
412 if (ulMinorVer > 50)
413 g_enmVGDrvNtVer = VGDRVNTVER_WINNT351;
414 else if (ulMinorVer >= 50)
415 g_enmVGDrvNtVer = VGDRVNTVER_WINNT350;
416 else
417 g_enmVGDrvNtVer = VGDRVNTVER_WINNT310;
418 break;
419 default:
420 /* Major versions above 6 gets classified as windows 10. */
421 if (ulMajorVer > 6)
422 g_enmVGDrvNtVer = VGDRVNTVER_WIN10;
423 else
424 {
425 RTLogBackdoorPrintf("At least Windows NT 3.10 required! Found %u.%u!\n", ulMajorVer, ulMinorVer);
426 rcNt = STATUS_DRIVER_UNABLE_TO_LOAD;
427 }
428 break;
429 }
430 if (NT_SUCCESS(rcNt))
431 {
432 /*
433 * Dynamically resolve symbols not present in NT4.
434 */
435 RTDBGKRNLINFO hKrnlInfo;
436 rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0 /*fFlags*/);
437 if (RT_SUCCESS(rc))
438 {
439 g_pfnKeRegisterBugCheckCallback = (decltype(KeRegisterBugCheckCallback) *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeRegisterBugCheckCallback");
440 g_pfnKeDeregisterBugCheckCallback = (decltype(KeDeregisterBugCheckCallback) *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeDeregisterBugCheckCallback");
441 g_pauKiBugCheckData = (uintptr_t const *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KiBugCheckData");
442 g_pfnPoCallDriver = (decltype(PoCallDriver) *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "PoCallDriver");
443 g_pfnPoStartNextPowerIrp = (decltype(PoStartNextPowerIrp) *) RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "PoStartNextPowerIrp");
444#ifdef TARGET_NT4
445 if (g_enmVGDrvNtVer > VGDRVNTVER_WINNT4)
446#endif
447 {
448 if (!g_pfnPoCallDriver) { LogRelFunc(("Missing PoCallDriver!\n")); rc = VERR_SYMBOL_NOT_FOUND; }
449 if (!g_pfnPoStartNextPowerIrp) { LogRelFunc(("Missing PoStartNextPowerIrp!\n")); rc = VERR_SYMBOL_NOT_FOUND; }
450 }
451
452#ifdef TARGET_NT4
453 g_pfnHalAssignSlotResources = (decltype(HalAssignSlotResources) *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "HalAssignSlotResources");
454 if (!g_pfnHalAssignSlotResources && g_enmVGDrvNtVer >= VGDRVNTVER_WINNT350 && g_enmVGDrvNtVer < VGDRVNTVER_WIN2K)
455 {
456 RTLogBackdoorPrintf("VBoxGuest: Missing HalAssignSlotResources!\n");
457 rc = VERR_SYMBOL_NOT_FOUND;
458 }
459
460 g_pfnHalGetBusDataByOffset = (decltype(HalGetBusDataByOffset) *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "HalGetBusDataByOffset");
461 if (!g_pfnHalGetBusDataByOffset && g_enmVGDrvNtVer >= VGDRVNTVER_WINNT350 && g_enmVGDrvNtVer < VGDRVNTVER_WIN2K)
462 {
463 RTLogBackdoorPrintf("VBoxGuest: Missing HalGetBusDataByOffset!\n");
464 rc = VERR_SYMBOL_NOT_FOUND;
465 }
466 if (!g_pfnHalGetBusDataByOffset)
467 g_pfnHalGetBusDataByOffset = vgdrvNt31GetBusDataByOffset;
468
469 g_pfnHalSetBusDataByOffset = (decltype(HalSetBusDataByOffset) *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "HalSetBusDataByOffset");
470 if (!g_pfnHalSetBusDataByOffset && g_enmVGDrvNtVer >= VGDRVNTVER_WINNT350 && g_enmVGDrvNtVer < VGDRVNTVER_WIN2K)
471 {
472 RTLogBackdoorPrintf("VBoxGuest: Missing HalSetBusDataByOffset!\n");
473 rc = VERR_SYMBOL_NOT_FOUND;
474 }
475 if (!g_pfnHalSetBusDataByOffset)
476 g_pfnHalSetBusDataByOffset = vgdrvNt31SetBusDataByOffset;
477#endif
478 RTR0DbgKrnlInfoRelease(hKrnlInfo);
479 }
480 if (RT_SUCCESS(rc))
481 {
482 /*
483 * Setup the driver entry points in pDrvObj.
484 */
485 pDrvObj->DriverUnload = vgdrvNtUnload;
486 pDrvObj->MajorFunction[IRP_MJ_CREATE] = vgdrvNtCreate;
487 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = vgdrvNtClose;
488 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vgdrvNtDeviceControl;
489 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = vgdrvNtInternalIOCtl;
490 /** @todo Need to call IoRegisterShutdownNotification or
491 * IoRegisterLastChanceShutdownNotification, possibly hooking the
492 * HalReturnToFirmware import in NTOSKRNL on older systems (<= ~NT4) and
493 * check for power off requests. */
494 pDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = vgdrvNtShutdown;
495 pDrvObj->MajorFunction[IRP_MJ_READ] = vgdrvNtNotSupportedStub;
496 pDrvObj->MajorFunction[IRP_MJ_WRITE] = vgdrvNtNotSupportedStub;
497#ifdef TARGET_NT4
498 if (g_enmVGDrvNtVer <= VGDRVNTVER_WINNT4)
499 rcNt = vgdrvNt4CreateDevice(pDrvObj, pRegPath);
500 else
501#endif
502 {
503 pDrvObj->MajorFunction[IRP_MJ_PNP] = vgdrvNtNt5PlusPnP;
504 pDrvObj->MajorFunction[IRP_MJ_POWER] = vgdrvNtNt5PlusPower;
505 pDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = vgdrvNtNt5PlusSystemControl;
506 pDrvObj->DriverExtension->AddDevice = vgdrvNtNt5PlusAddDevice;
507 }
508 if (NT_SUCCESS(rcNt))
509 {
510 /*
511 * Try register the bugcheck callback (non-fatal).
512 */
513 if ( g_pfnKeRegisterBugCheckCallback
514 && g_pfnKeDeregisterBugCheckCallback)
515 {
516 AssertCompile(BufferEmpty == 0);
517 KeInitializeCallbackRecord(&g_BugCheckCallbackRec);
518 if (g_pfnKeRegisterBugCheckCallback(&g_BugCheckCallbackRec, vgdrvNtBugCheckCallback,
519 NULL, 0, (PUCHAR)"VBoxGuest"))
520 g_fBugCheckCallbackRegistered = true;
521 else
522 g_fBugCheckCallbackRegistered = false;
523 }
524 else
525 Assert(g_pfnKeRegisterBugCheckCallback == NULL && g_pfnKeDeregisterBugCheckCallback == NULL);
526
527 LogFlowFunc(("Returning %#x\n", rcNt));
528 return rcNt;
529 }
530 }
531 else
532 rcNt = STATUS_PROCEDURE_NOT_FOUND;
533 }
534
535 /*
536 * Failed.
537 */
538 LogRelFunc(("Failed! rcNt=%#x\n", rcNt));
539 VGDrvCommonDestroyLoggers();
540 RTR0Term();
541 return rcNt;
542}
543
544
545/**
546 * Translates our internal NT version enum to VBox OS.
547 *
548 * @returns VBox OS type.
549 * @param enmNtVer The NT version.
550 */
551static VBOXOSTYPE vgdrvNtVersionToOSType(VGDRVNTVER enmNtVer)
552{
553 VBOXOSTYPE enmOsType;
554 switch (enmNtVer)
555 {
556 case VGDRVNTVER_WINNT310: enmOsType = VBOXOSTYPE_WinNT3x; break;
557 case VGDRVNTVER_WINNT350: enmOsType = VBOXOSTYPE_WinNT3x; break;
558 case VGDRVNTVER_WINNT351: enmOsType = VBOXOSTYPE_WinNT3x; break;
559 case VGDRVNTVER_WINNT4: enmOsType = VBOXOSTYPE_WinNT4; break;
560 case VGDRVNTVER_WIN2K: enmOsType = VBOXOSTYPE_Win2k; break;
561 case VGDRVNTVER_WINXP: enmOsType = VBOXOSTYPE_WinXP; break;
562 case VGDRVNTVER_WIN2K3: enmOsType = VBOXOSTYPE_Win2k3; break;
563 case VGDRVNTVER_WINVISTA: enmOsType = VBOXOSTYPE_WinVista; break;
564 case VGDRVNTVER_WIN7: enmOsType = VBOXOSTYPE_Win7; break;
565 case VGDRVNTVER_WIN8: enmOsType = VBOXOSTYPE_Win8; break;
566 case VGDRVNTVER_WIN81: enmOsType = VBOXOSTYPE_Win81; break;
567 case VGDRVNTVER_WIN10: enmOsType = VBOXOSTYPE_Win10; break;
568 case VGDRVNTVER_WIN11: enmOsType = VBOXOSTYPE_Win11_x64; break;
569
570 default:
571 /* We don't know, therefore NT family. */
572 enmOsType = VBOXOSTYPE_WinNT;
573 break;
574 }
575#if ARCH_BITS == 64
576 enmOsType = (VBOXOSTYPE)((int)enmOsType | VBOXOSTYPE_x64);
577#endif
578 return enmOsType;
579}
580
581
582/**
583 * Does the fundamental device extension initialization.
584 *
585 * @returns NT status.
586 * @param pDevExt The device extension.
587 * @param pDevObj The device object.
588 */
589static NTSTATUS vgdrvNtInitDevExtFundament(PVBOXGUESTDEVEXTWIN pDevExt, PDEVICE_OBJECT pDevObj)
590{
591 RT_ZERO(*pDevExt);
592
593 KeInitializeSpinLock(&pDevExt->MouseEventAccessSpinLock);
594 pDevExt->pDeviceObject = pDevObj;
595 pDevExt->enmPrevDevState = VGDRVNTDEVSTATE_STOPPED;
596 pDevExt->enmDevState = VGDRVNTDEVSTATE_STOPPED;
597
598 int rc = RTCritSectRwInit(&pDevExt->SessionCreateCritSect);
599 if (RT_SUCCESS(rc))
600 {
601 rc = VGDrvCommonInitDevExtFundament(&pDevExt->Core);
602 if (RT_SUCCESS(rc))
603 {
604 LogFlow(("vgdrvNtInitDevExtFundament: returning success\n"));
605 return STATUS_SUCCESS;
606 }
607
608 RTCritSectRwDelete(&pDevExt->SessionCreateCritSect);
609 }
610 Log(("vgdrvNtInitDevExtFundament: failed: rc=%Rrc\n", rc));
611 return STATUS_UNSUCCESSFUL;
612}
613
614
615/**
616 * Counter part to vgdrvNtInitDevExtFundament.
617 *
618 * @param pDevExt The device extension.
619 */
620static void vgdrvNtDeleteDevExtFundament(PVBOXGUESTDEVEXTWIN pDevExt)
621{
622 LogFlow(("vgdrvNtDeleteDevExtFundament:\n"));
623 VGDrvCommonDeleteDevExtFundament(&pDevExt->Core);
624 RTCritSectRwDelete(&pDevExt->SessionCreateCritSect);
625}
626
627
628#ifdef LOG_ENABLED
629/**
630 * Debug helper to dump a device resource list.
631 *
632 * @param pResourceList list of device resources.
633 */
634static void vgdrvNtShowDeviceResources(PCM_RESOURCE_LIST pRsrcList)
635{
636 for (uint32_t iList = 0; iList < pRsrcList->Count; iList++)
637 {
638 PCM_FULL_RESOURCE_DESCRIPTOR pList = &pRsrcList->List[iList];
639 LogFunc(("List #%u: InterfaceType=%#x BusNumber=%#x ListCount=%u ListRev=%#x ListVer=%#x\n",
640 iList, pList->InterfaceType, pList->BusNumber, pList->PartialResourceList.Count,
641 pList->PartialResourceList.Revision, pList->PartialResourceList.Version ));
642
643 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResource = pList->PartialResourceList.PartialDescriptors;
644 for (ULONG i = 0; i < pList->PartialResourceList.Count; ++i, ++pResource)
645 {
646 ULONG uType = pResource->Type;
647 static char const * const s_apszName[] =
648 {
649 "CmResourceTypeNull",
650 "CmResourceTypePort",
651 "CmResourceTypeInterrupt",
652 "CmResourceTypeMemory",
653 "CmResourceTypeDma",
654 "CmResourceTypeDeviceSpecific",
655 "CmResourceTypeuBusNumber",
656 "CmResourceTypeDevicePrivate",
657 "CmResourceTypeAssignedResource",
658 "CmResourceTypeSubAllocateFrom",
659 };
660
661 if (uType < RT_ELEMENTS(s_apszName))
662 LogFunc((" %.30s Flags=%#x Share=%#x", s_apszName[uType], pResource->Flags, pResource->ShareDisposition));
663 else
664 LogFunc((" Type=%#x Flags=%#x Share=%#x", uType, pResource->Flags, pResource->ShareDisposition));
665 switch (uType)
666 {
667 case CmResourceTypePort:
668 case CmResourceTypeMemory:
669 Log((" Start %#RX64, length=%#x\n", pResource->u.Port.Start.QuadPart, pResource->u.Port.Length));
670 break;
671
672 case CmResourceTypeInterrupt:
673 Log((" Level=%X, vector=%#x, affinity=%#x\n",
674 pResource->u.Interrupt.Level, pResource->u.Interrupt.Vector, pResource->u.Interrupt.Affinity));
675 break;
676
677 case CmResourceTypeDma:
678 Log((" Channel %d, Port %#x\n", pResource->u.Dma.Channel, pResource->u.Dma.Port));
679 break;
680
681 default:
682 Log(("\n"));
683 break;
684 }
685 }
686 }
687}
688#endif /* LOG_ENABLED */
689
690
691/**
692 * Helper to scan the PCI resource list and remember stuff.
693 *
694 * @param pDevExt The device extension.
695 * @param pResList Resource list
696 * @param fTranslated Whether the addresses are translated or not.
697 */
698static NTSTATUS vgdrvNtScanPCIResourceList(PVBOXGUESTDEVEXTWIN pDevExt, PCM_RESOURCE_LIST pResList, bool fTranslated)
699{
700 LogFlowFunc(("Found %d resources\n", pResList->List->PartialResourceList.Count));
701 PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialData = NULL;
702 bool fGotIrq = false;
703 bool fGotMmio = false;
704 bool fGotIoPorts = false;
705 NTSTATUS rc = STATUS_SUCCESS;
706 for (ULONG i = 0; i < pResList->List->PartialResourceList.Count; i++)
707 {
708 pPartialData = &pResList->List->PartialResourceList.PartialDescriptors[i];
709 switch (pPartialData->Type)
710 {
711 case CmResourceTypePort:
712 LogFlowFunc(("I/O range: Base=%#RX64, length=%08x\n",
713 pPartialData->u.Port.Start.QuadPart, pPartialData->u.Port.Length));
714 /* Save the first I/O port base. */
715 if (!fGotIoPorts)
716 {
717 pDevExt->Core.IOPortBase = (RTIOPORT)pPartialData->u.Port.Start.LowPart;
718 fGotIoPorts = true;
719 LogFunc(("I/O range for VMMDev found! Base=%#RX64, length=%08x\n",
720 pPartialData->u.Port.Start.QuadPart, pPartialData->u.Port.Length));
721 }
722 else
723 LogRelFunc(("More than one I/O port range?!?\n"));
724 break;
725
726 case CmResourceTypeInterrupt:
727 LogFunc(("Interrupt: Level=%x, vector=%x, mode=%x\n",
728 pPartialData->u.Interrupt.Level, pPartialData->u.Interrupt.Vector, pPartialData->Flags));
729 if (!fGotIrq)
730 {
731 /* Save information. */
732 pDevExt->uInterruptLevel = pPartialData->u.Interrupt.Level;
733 pDevExt->uInterruptVector = pPartialData->u.Interrupt.Vector;
734 pDevExt->fInterruptAffinity = pPartialData->u.Interrupt.Affinity;
735
736 /* Check interrupt mode. */
737 if (pPartialData->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
738 pDevExt->enmInterruptMode = Latched;
739 else
740 pDevExt->enmInterruptMode = LevelSensitive;
741 fGotIrq = true;
742 LogFunc(("Interrupt for VMMDev found! Vector=%#x Level=%#x Affinity=%zx Mode=%d\n", pDevExt->uInterruptVector,
743 pDevExt->uInterruptLevel, pDevExt->fInterruptAffinity, pDevExt->enmInterruptMode));
744 }
745 else
746 LogFunc(("More than one IRQ resource!\n"));
747 break;
748
749 case CmResourceTypeMemory:
750 LogFlowFunc(("Memory range: Base=%#RX64, length=%08x\n",
751 pPartialData->u.Memory.Start.QuadPart, pPartialData->u.Memory.Length));
752 /* We only care about the first read/write memory range. */
753 if ( !fGotMmio
754 && (pPartialData->Flags & CM_RESOURCE_MEMORY_WRITEABILITY_MASK) == CM_RESOURCE_MEMORY_READ_WRITE)
755 {
756 /* Save physical MMIO base + length for VMMDev. */
757 pDevExt->uVmmDevMemoryPhysAddr = pPartialData->u.Memory.Start;
758 pDevExt->cbVmmDevMemory = (ULONG)pPartialData->u.Memory.Length;
759
760 if (!fTranslated)
761 {
762 /* Technically we need to make the HAL translate the address. since we
763 didn't used to do this and it probably just returns the input address,
764 we allow ourselves to ignore failures. */
765 ULONG uAddressSpace = 0;
766 PHYSICAL_ADDRESS PhysAddr = pPartialData->u.Memory.Start;
767 if (HalTranslateBusAddress(pResList->List->InterfaceType, pResList->List->BusNumber, PhysAddr,
768 &uAddressSpace, &PhysAddr))
769 {
770 Log(("HalTranslateBusAddress(%#RX64) -> %RX64, type %#x\n",
771 pPartialData->u.Memory.Start.QuadPart, PhysAddr.QuadPart, uAddressSpace));
772 if (pPartialData->u.Memory.Start.QuadPart != PhysAddr.QuadPart)
773 pDevExt->uVmmDevMemoryPhysAddr = PhysAddr;
774 }
775 else
776 Log(("HalTranslateBusAddress(%#RX64) -> failed!\n", pPartialData->u.Memory.Start.QuadPart));
777 }
778
779 fGotMmio = true;
780 LogFunc(("Found memory range for VMMDev! Base = %#RX64, Length = %08x\n",
781 pPartialData->u.Memory.Start.QuadPart, pPartialData->u.Memory.Length));
782 }
783 else if ( (pPartialData->Flags & CM_RESOURCE_MEMORY_WRITEABILITY_MASK) == CM_RESOURCE_MEMORY_READ_WRITE
784 /* Make sure that we only treat this as MMIO interface if we have the exact MMIO size.
785 * We have a different (bigger) memory area (for VMM) which we don't want to be
786 * detected as MMIO region. This otherwise will break running on x86 guests. */
787 && (VMMDEV_MMIO_SIZE == pPartialData->u.Memory.Length))
788 {
789 /* Treat as MMIO request interface. */
790 /* Save physical MMIO base + length for VMMDev. */
791 pDevExt->GCPhysMmioReq = pPartialData->u.Memory.Start;
792 pDevExt->cbMmioReq = (ULONG)pPartialData->u.Memory.Length;
793
794 if (!fTranslated)
795 {
796 /* Technically we need to make the HAL translate the address. since we
797 didn't used to do this and it probably just returns the input address,
798 we allow ourselves to ignore failures. */
799 ULONG uAddressSpace = 0;
800 PHYSICAL_ADDRESS PhysAddr = pPartialData->u.Memory.Start;
801 if (HalTranslateBusAddress(pResList->List->InterfaceType, pResList->List->BusNumber, PhysAddr,
802 &uAddressSpace, &PhysAddr))
803 {
804 Log(("HalTranslateBusAddress(%#RX64) -> %RX64, type %#x\n",
805 pPartialData->u.Memory.Start.QuadPart, PhysAddr.QuadPart, uAddressSpace));
806 if (pPartialData->u.Memory.Start.QuadPart != PhysAddr.QuadPart)
807 pDevExt->GCPhysMmioReq = PhysAddr;
808 }
809 else
810 Log(("HalTranslateBusAddress(%#RX64) -> failed!\n", pPartialData->u.Memory.Start.QuadPart));
811 }
812
813 LogFunc(("Found memory range for VMMDev MMIO request interface! Base = %#RX64, Length = %08x\n",
814 pPartialData->u.Memory.Start.QuadPart, pPartialData->u.Memory.Length));
815 }
816 else
817 LogFunc(("Ignoring memory: Flags=%08x Base=%#RX64\n",
818 pPartialData->Flags, pPartialData->u.Memory.Start.QuadPart));
819 break;
820
821 default:
822 LogFunc(("Unhandled resource found, type=%d\n", pPartialData->Type));
823 break;
824 }
825 }
826 return rc;
827}
828
829
830#ifdef TARGET_NT4
831
832/**
833 * Scans the PCI resources on NT 3.1.
834 *
835 * @returns STATUS_SUCCESS or STATUS_DEVICE_CONFIGURATION_ERROR.
836 * @param pDevExt The device extension.
837 * @param uBus The bus number.
838 * @param uSlot The PCI slot to scan.
839 */
840static NTSTATUS vgdrvNt31ScanSlotResources(PVBOXGUESTDEVEXTWIN pDevExt, ULONG uBus, ULONG uSlot)
841{
842 /*
843 * Disable memory mappings so we can determin the BAR lengths
844 * without upsetting other mappings.
845 */
846 uint16_t fCmd = 0;
847 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmd, VBOX_PCI_COMMAND, sizeof(fCmd));
848 if (fCmd & VBOX_PCI_COMMAND_MEMORY)
849 {
850 uint16_t fCmdTmp = fCmd & ~VBOX_PCI_COMMAND_MEMORY;
851 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmdTmp, VBOX_PCI_COMMAND, sizeof(fCmdTmp));
852 }
853
854 /*
855 * Scan the address resources first.
856 */
857 uint32_t aBars[6] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX };
858 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &aBars, VBOX_PCI_BASE_ADDRESS_0, sizeof(aBars));
859
860 bool fGotMmio = false;
861 bool fGotIoPorts = false;
862 for (uint32_t i = 0; i < RT_ELEMENTS(aBars); i++)
863 {
864 uint32_t uBar = aBars[i];
865 if (uBar == UINT32_MAX)
866 continue;
867 if ((uBar & 1) == PCI_ADDRESS_SPACE_IO)
868 {
869 uint32_t uAddr = uBar & UINT32_C(0xfffffffc);
870 if (!uAddr)
871 continue;
872 if (!fGotIoPorts)
873 {
874 pDevExt->Core.IOPortBase = (uint16_t)uAddr & UINT16_C(0xfffc);
875 fGotIoPorts = true;
876 LogFunc(("I/O range for VMMDev found in BAR%u! %#x\n", i, pDevExt->Core.IOPortBase));
877 }
878 else
879 LogRelFunc(("More than one I/O port range?!? BAR%u=%#x\n", i, uBar));
880 }
881 else
882 {
883 uint32_t uAddr = uBar & UINT32_C(0xfffffff0);
884 if (!uAddr)
885 continue;
886
887 if (!fGotMmio)
888 {
889 /* Figure the length by trying to set all address bits and seeing
890 how many we're allowed to set. */
891 uint32_t iBit = 4;
892 while (!(uAddr & RT_BIT_32(iBit)))
893 iBit++;
894
895 uint32_t const offPciBar = VBOX_PCI_BASE_ADDRESS_0 + i * 4;
896 uint32_t uTmpBar = uBar | ((RT_BIT_32(iBit) - 1) & UINT32_C(0xfffffff0));
897 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &uTmpBar, offPciBar, sizeof(uTmpBar));
898 uTmpBar = uBar;
899 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &uTmpBar, offPciBar, sizeof(uTmpBar));
900 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &uBar, offPciBar, sizeof(uBar));
901
902 while (iBit > 4 && (uTmpBar & RT_BIT_32(iBit - 1)))
903 iBit--;
904
905 /* got it */
906 pDevExt->cbVmmDevMemory = RT_BIT_32(iBit);
907 pDevExt->uVmmDevMemoryPhysAddr.QuadPart = uAddr;
908 fGotMmio = true;
909 LogFunc(("Found memory range for VMMDev in BAR%u! %#RX64 LB %#x (raw %#x)\n",
910 i, pDevExt->uVmmDevMemoryPhysAddr.QuadPart, pDevExt->cbVmmDevMemory, uBar));
911 }
912 else
913 LogFunc(("Ignoring memory: BAR%u=%#x\n", i, uBar));
914 }
915 }
916
917 /*
918 * Get the IRQ
919 */
920 struct
921 {
922 uint8_t bInterruptLine;
923 uint8_t bInterruptPin;
924 } Buf = { 0, 0 };
925 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &Buf, VBOX_PCI_INTERRUPT_LINE, sizeof(Buf));
926 if (Buf.bInterruptPin != 0)
927 {
928 pDevExt->uInterruptVector = Buf.bInterruptLine;
929 pDevExt->uInterruptLevel = Buf.bInterruptLine;
930 pDevExt->enmInterruptMode = LevelSensitive;
931 pDevExt->fInterruptAffinity = RT_BIT_32(RTMpGetCount()) - 1;
932 LogFunc(("Interrupt for VMMDev found! Vector=%#x Level=%#x Affinity=%zx Mode=%d\n",
933 pDevExt->uInterruptVector, pDevExt->uInterruptLevel, pDevExt->fInterruptAffinity, pDevExt->enmInterruptMode));
934 }
935
936 /*
937 * Got what we need?
938 */
939 if (fGotIoPorts && (!fGotMmio || Buf.bInterruptPin != 0))
940 {
941 /*
942 * Enable both MMIO, I/O space and busmastering so we can use the device.
943 */
944 uint16_t fCmdNew = fCmd | VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY | VBOX_PCI_COMMAND_MASTER;
945 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmdNew, VBOX_PCI_COMMAND, sizeof(fCmdNew));
946
947 return STATUS_SUCCESS;
948 }
949
950 /* No. Complain, restore device command value and return failure. */
951 if (!fGotIoPorts)
952 LogRel(("VBoxGuest: Did not find I/O port range: %#x %#x %#x %#x %#x %#x\n",
953 aBars[0], aBars[1], aBars[2], aBars[3], aBars[4], aBars[5]));
954 if (!fGotMmio || Buf.bInterruptPin != 0)
955 LogRel(("VBoxGuest: Got MMIO but no interrupts!\n"));
956
957 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmd, VBOX_PCI_COMMAND, sizeof(fCmd));
958 return STATUS_DEVICE_CONFIGURATION_ERROR;
959}
960
961#endif /* TARGET_NT4 */
962
963/**
964 * Unmaps the VMMDev I/O range from kernel space.
965 *
966 * @param pDevExt The device extension.
967 */
968static void vgdrvNtUnmapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt)
969{
970 LogFlowFunc(("pVMMDevMemory = %#x\n", pDevExt->Core.pVMMDevMemory));
971 if (pDevExt->Core.pVMMDevMemory)
972 {
973 MmUnmapIoSpace((void*)pDevExt->Core.pVMMDevMemory, pDevExt->cbVmmDevMemory);
974 pDevExt->Core.pVMMDevMemory = NULL;
975 }
976
977 pDevExt->uVmmDevMemoryPhysAddr.QuadPart = 0;
978 pDevExt->cbVmmDevMemory = 0;
979}
980
981
982/**
983 * Unmaps the MMIO request interface range from kernel space.
984 *
985 * @param pDevExt The device extension.
986 */
987static void vgdrvNtUnmapVMMDevMmioReq(PVBOXGUESTDEVEXTWIN pDevExt)
988{
989 LogFlowFunc(("pMmioReq = %#p\n", pDevExt->Core.pMmioReq));
990 if (pDevExt->Core.pMmioReq)
991 {
992 MmUnmapIoSpace((void*)pDevExt->Core.pMmioReq, pDevExt->cbMmioReq);
993 pDevExt->Core.pMmioReq = NULL;
994 pDevExt->Core.pMmioReqFast = NULL;
995 }
996
997 pDevExt->GCPhysMmioReq.QuadPart = 0;
998 pDevExt->cbMmioReq = 0;
999}
1000
1001
1002/**
1003 * Maps the I/O space from VMMDev to virtual kernel address space.
1004 *
1005 * @return NTSTATUS
1006 *
1007 * @param pDevExt The device extension.
1008 * @param PhysAddr Physical address to map.
1009 * @param cbToMap Number of bytes to map.
1010 * @param ppvMMIOBase Pointer of mapped I/O base.
1011 * @param pcbMMIO Length of mapped I/O base.
1012 */
1013static NTSTATUS vgdrvNtMapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS PhysAddr, ULONG cbToMap,
1014 void **ppvMMIOBase, uint32_t *pcbMMIO)
1015{
1016 AssertPtrReturn(pDevExt, STATUS_INVALID_PARAMETER);
1017 AssertPtrReturn(ppvMMIOBase, STATUS_INVALID_PARAMETER);
1018 /* pcbMMIO is optional. */
1019
1020 NTSTATUS rc = STATUS_SUCCESS;
1021 if (PhysAddr.LowPart > 0) /* We're mapping below 4GB. */
1022 {
1023 VMMDevMemory *pVMMDevMemory = (VMMDevMemory *)MmMapIoSpace(PhysAddr, cbToMap, MmNonCached);
1024 LogFlowFunc(("pVMMDevMemory = %#x\n", pVMMDevMemory));
1025 if (pVMMDevMemory)
1026 {
1027 LogFunc(("VMMDevMemory: Version = %#x, Size = %d\n", pVMMDevMemory->u32Version, pVMMDevMemory->u32Size));
1028
1029 /* Check version of the structure; do we have the right memory version? */
1030 if (pVMMDevMemory->u32Version == VMMDEV_MEMORY_VERSION)
1031 {
1032 /* Save results. */
1033 *ppvMMIOBase = pVMMDevMemory;
1034 if (pcbMMIO) /* Optional. */
1035 *pcbMMIO = pVMMDevMemory->u32Size;
1036
1037 LogFlowFunc(("VMMDevMemory found and mapped! pvMMIOBase = 0x%p\n", *ppvMMIOBase));
1038 }
1039 else
1040 {
1041 /* Not our version, refuse operation and unmap the memory. */
1042 LogFunc(("Wrong version (%u), refusing operation!\n", pVMMDevMemory->u32Version));
1043
1044 vgdrvNtUnmapVMMDevMemory(pDevExt);
1045 rc = STATUS_UNSUCCESSFUL;
1046 }
1047 }
1048 else
1049 rc = STATUS_UNSUCCESSFUL;
1050 }
1051 return rc;
1052}
1053
1054
1055/**
1056 * Maps the I/O space from VMMDev to virtual kernel address space.
1057 *
1058 * @return NTSTATUS
1059 *
1060 * @param pDevExt The device extension.
1061 * @param GCPhysMmioReq Physical address to map.
1062 * @param cbToMap Number of bytes to map.
1063 * @param ppvMmioReq Pointer of mapped I/O base.
1064 */
1065static NTSTATUS vgdrvNtMapVMMDevMmioReq(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS GCPhysMmioReq, ULONG cbToMap,
1066 void **ppvMmioReq)
1067{
1068 AssertPtrReturn(pDevExt, STATUS_INVALID_PARAMETER);
1069 AssertPtrReturn(ppvMmioReq, STATUS_INVALID_PARAMETER);
1070
1071 NTSTATUS rc = STATUS_SUCCESS;
1072 if (GCPhysMmioReq.QuadPart != 0)
1073 {
1074 void *pvMmioReq = MmMapIoSpace(GCPhysMmioReq, cbToMap, MmNonCached);
1075 LogFlowFunc(("pvMmioReq = %p\n", pvMmioReq));
1076 if (pvMmioReq)
1077 {
1078 /* Save results. */
1079 *ppvMmioReq = pvMmioReq;
1080 LogFlowFunc(("MMIO request interface found and mapped! pvMmioReq = 0x%p\n", pvMmioReq));
1081 }
1082 else
1083 rc = STATUS_UNSUCCESSFUL;
1084 }
1085 return rc;
1086}
1087
1088
1089/**
1090 * Sets up the device and its resources.
1091 *
1092 * @param pDevExt Our device extension data.
1093 * @param pDevObj The device object.
1094 * @param pIrp The request packet if NT5+, NULL for NT4 and earlier.
1095 * @param pDrvObj The driver object for NT4, NULL for NT5+.
1096 * @param pRegPath The registry path for NT4, NULL for NT5+.
1097 */
1098static NTSTATUS vgdrvNtSetupDevice(PVBOXGUESTDEVEXTWIN pDevExt, PDEVICE_OBJECT pDevObj,
1099 PIRP pIrp, PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1100{
1101 LogFlowFunc(("ENTER: pDevExt=%p pDevObj=%p pIrq=%p pDrvObj=%p pRegPath=%p\n", pDevExt, pDevObj, pIrp, pDrvObj, pRegPath));
1102
1103 NTSTATUS rcNt;
1104 if (!pIrp)
1105 {
1106#ifdef TARGET_NT4
1107 /*
1108 * NT4, NT3.x: Let's have a look at what our PCI adapter offers.
1109 */
1110 LogFlowFunc(("Starting to scan PCI resources of VBoxGuest ...\n"));
1111
1112 /* Assign the PCI resources. */
1113 UNICODE_STRING ClassName;
1114 RtlInitUnicodeString(&ClassName, L"VBoxGuestAdapter");
1115 PCM_RESOURCE_LIST pResourceList = NULL;
1116 if (g_pfnHalAssignSlotResources)
1117 {
1118 rcNt = g_pfnHalAssignSlotResources(pRegPath, &ClassName, pDrvObj, pDevObj, PCIBus, pDevExt->uBus, pDevExt->uSlot,
1119 &pResourceList);
1120# ifdef LOG_ENABLED
1121 if (pResourceList)
1122 vgdrvNtShowDeviceResources(pResourceList);
1123# endif
1124 if (NT_SUCCESS(rcNt))
1125 {
1126 rcNt = vgdrvNtScanPCIResourceList(pDevExt, pResourceList, false /*fTranslated*/);
1127 ExFreePool(pResourceList);
1128 }
1129 }
1130 else
1131 rcNt = vgdrvNt31ScanSlotResources(pDevExt, pDevExt->uBus, pDevExt->uSlot);
1132
1133# else /* !TARGET_NT4 */
1134 AssertFailed();
1135 RT_NOREF(pDevObj, pDrvObj, pRegPath);
1136 rcNt = STATUS_INTERNAL_ERROR;
1137# endif /* !TARGET_NT4 */
1138 }
1139 else
1140 {
1141 /*
1142 * NT5+: Scan the PCI resource list from the IRP.
1143 */
1144 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1145# ifdef LOG_ENABLED
1146 vgdrvNtShowDeviceResources(pStack->Parameters.StartDevice.AllocatedResourcesTranslated);
1147# endif
1148 rcNt = vgdrvNtScanPCIResourceList(pDevExt, pStack->Parameters.StartDevice.AllocatedResourcesTranslated,
1149 true /*fTranslated*/);
1150 }
1151 if (NT_SUCCESS(rcNt))
1152 {
1153 /*
1154 * Map physical address of VMMDev memory into MMIO region
1155 * and init the common device extension bits.
1156 */
1157 void *pvMMIOBase = NULL;
1158 uint32_t cbMMIO = 0;
1159 rcNt = vgdrvNtMapVMMDevMemory(pDevExt,
1160 pDevExt->uVmmDevMemoryPhysAddr,
1161 pDevExt->cbVmmDevMemory,
1162 &pvMMIOBase,
1163 &cbMMIO);
1164 if (NT_SUCCESS(rcNt))
1165 {
1166 pDevExt->Core.pVMMDevMemory = (VMMDevMemory *)pvMMIOBase;
1167
1168 void *pvMmioReq = NULL;
1169 rcNt = vgdrvNtMapVMMDevMmioReq(pDevExt, pDevExt->GCPhysMmioReq, pDevExt->cbMmioReq, &pvMmioReq);
1170 if (NT_SUCCESS(rcNt))
1171 {
1172 LogFunc(("pvMMIOBase=0x%p, pDevExt=0x%p, pDevExt->Core.pVMMDevMemory=0x%p\n",
1173 pvMMIOBase, pDevExt, pDevExt ? pDevExt->Core.pVMMDevMemory : NULL));
1174
1175 int vrc = VGDrvCommonInitDevExtResources(&pDevExt->Core,
1176 pDevExt->Core.IOPortBase,
1177 pvMmioReq,
1178 pvMMIOBase, cbMMIO,
1179 vgdrvNtVersionToOSType(g_enmVGDrvNtVer),
1180 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
1181 if (RT_SUCCESS(vrc))
1182 {
1183
1184 vrc = VbglR0GRAlloc((VMMDevRequestHeader **)&pDevExt->pPowerStateRequest,
1185 sizeof(VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
1186 if (RT_SUCCESS(vrc))
1187 {
1188 /*
1189 * Register DPC and ISR.
1190 */
1191 LogFlowFunc(("Initializing DPC/ISR (pDevObj=%p)...\n", pDevExt->pDeviceObject));
1192 IoInitializeDpcRequest(pDevExt->pDeviceObject, vgdrvNtDpcHandler);
1193
1194 ULONG uInterruptVector = pDevExt->uInterruptVector;
1195 KIRQL uHandlerIrql = (KIRQL)pDevExt->uInterruptLevel;
1196 #ifdef TARGET_NT4
1197 if (!pIrp)
1198 {
1199 /* NT4: Get an interrupt vector. Only proceed if the device provides an interrupt. */
1200 if ( uInterruptVector
1201 || pDevExt->uInterruptLevel)
1202 {
1203 LogFlowFunc(("Getting interrupt vector (HAL): Bus=%u, IRQL=%u, Vector=%u\n",
1204 pDevExt->uBus, pDevExt->uInterruptLevel, pDevExt->uInterruptVector));
1205 uInterruptVector = HalGetInterruptVector(g_enmVGDrvNtVer == VGDRVNTVER_WINNT310 ? Isa : PCIBus,
1206 pDevExt->uBus,
1207 pDevExt->uInterruptLevel,
1208 pDevExt->uInterruptVector,
1209 &uHandlerIrql,
1210 &pDevExt->fInterruptAffinity);
1211 LogFlowFunc(("HalGetInterruptVector returns vector=%u\n", uInterruptVector));
1212 }
1213 else
1214 LogFunc(("Device does not provide an interrupt!\n"));
1215 }
1216 #endif
1217 if (uInterruptVector)
1218 {
1219 LogFlowFunc(("Connecting interrupt (IntVector=%#u), uHandlerIrql=%u) ...\n",
1220 uInterruptVector, uHandlerIrql));
1221
1222 rcNt = IoConnectInterrupt(&pDevExt->pInterruptObject, /* Out: interrupt object. */
1223 vgdrvNtIsrHandler, /* Our ISR handler. */
1224 pDevExt, /* Device context. */
1225 NULL, /* Optional spinlock. */
1226 uInterruptVector, /* Interrupt vector. */
1227 uHandlerIrql, /* Irql. */
1228 uHandlerIrql, /* SynchronizeIrql. */
1229 pDevExt->enmInterruptMode, /* LevelSensitive or Latched. */
1230 TRUE, /* Shareable interrupt. */
1231 pDevExt->fInterruptAffinity, /* CPU affinity. */
1232 FALSE); /* Don't save FPU stack. */
1233 if (NT_ERROR(rcNt))
1234 LogFunc(("Could not connect interrupt: rcNt=%#x!\n", rcNt));
1235 }
1236 else
1237 LogFunc(("No interrupt vector found!\n"));
1238 if (NT_SUCCESS(rcNt))
1239 {
1240 /*
1241 * Once we've read configuration from register and host, we're finally read.
1242 */
1243 /** @todo clean up guest ring-3 logging, keeping it separate from the kernel to avoid sharing limits with it. */
1244 pDevExt->Core.fLoggingEnabled = true;
1245 vgdrvNtReadConfiguration(pDevExt);
1246
1247 /* Ready to rumble! */
1248 LogRelFunc(("Device is ready!\n"));
1249 pDevExt->enmDevState = VGDRVNTDEVSTATE_OPERATIONAL;
1250 pDevExt->enmPrevDevState = VGDRVNTDEVSTATE_OPERATIONAL;
1251 return STATUS_SUCCESS;
1252 }
1253
1254 pDevExt->pInterruptObject = NULL;
1255
1256 VbglR0GRFree(&pDevExt->pPowerStateRequest->header);
1257 pDevExt->pPowerStateRequest = NULL;
1258 }
1259 else
1260 {
1261 LogFunc(("Alloc for pPowerStateRequest failed, vrc=%Rrc\n", vrc));
1262 rcNt = STATUS_UNSUCCESSFUL;
1263 }
1264
1265 VGDrvCommonDeleteDevExtResources(&pDevExt->Core);
1266 }
1267 else
1268 {
1269 LogFunc(("Could not init device extension resources: vrc=%Rrc\n", vrc));
1270 rcNt = STATUS_DEVICE_CONFIGURATION_ERROR;
1271 }
1272 vgdrvNtUnmapVMMDevMmioReq(pDevExt);
1273 }
1274 else
1275 LogFunc(("Could not map MMIO request interface of VMMDec, rcNt=%#x\n", rcNt));
1276 vgdrvNtUnmapVMMDevMemory(pDevExt);
1277 }
1278 else
1279 LogFunc(("Could not map physical address of VMMDev, rcNt=%#x\n", rcNt));
1280 }
1281
1282 LogRelFunc(("Returned with rcNt=%#x\n", rcNt));
1283 return rcNt;
1284}
1285
1286
1287
1288
1289#ifdef TARGET_NT4
1290# define PCI_CFG_ADDR 0xcf8
1291# define PCI_CFG_DATA 0xcfc
1292
1293/**
1294 * NT 3.1 doesn't do PCI nor HalSetBusDataByOffset, this is our fallback.
1295 */
1296static ULONG NTAPI vgdrvNt31SetBusDataByOffset(BUS_DATA_TYPE enmBusDataType, ULONG idxBus, ULONG uSlot,
1297 void *pvData, ULONG offData, ULONG cbData)
1298{
1299 /*
1300 * Validate input a little bit.
1301 */
1302 RT_NOREF(enmBusDataType);
1303 Assert(idxBus <= 255);
1304 Assert(uSlot <= 255);
1305 Assert(offData <= 255);
1306 Assert(cbData > 0);
1307
1308 PCI_SLOT_NUMBER PciSlot;
1309 PciSlot.u.AsULONG = uSlot;
1310 uint32_t const idxAddrTop = UINT32_C(0x80000000)
1311 | (idxBus << 16)
1312 | (PciSlot.u.bits.DeviceNumber << 11)
1313 | (PciSlot.u.bits.FunctionNumber << 8);
1314
1315 /*
1316 * Write the given bytes.
1317 */
1318 uint8_t const *pbData = (uint8_t const *)pvData;
1319 uint32_t off = offData;
1320 uint32_t cbRet = 0;
1321
1322 /* Unaligned start. */
1323 if (off & 3)
1324 {
1325 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | (off & ~3));
1326 switch (off & 3)
1327 {
1328 case 1:
1329 ASMOutU8(PCI_CFG_DATA + 1, pbData[cbRet++]);
1330 if (cbRet >= cbData)
1331 break;
1332 RT_FALL_THRU();
1333 case 2:
1334 ASMOutU8(PCI_CFG_DATA + 2, pbData[cbRet++]);
1335 if (cbRet >= cbData)
1336 break;
1337 RT_FALL_THRU();
1338 case 3:
1339 ASMOutU8(PCI_CFG_DATA + 3, pbData[cbRet++]);
1340 break;
1341 }
1342 off = (off | 3) + 1;
1343 }
1344
1345 /* Bulk. */
1346 while (off < 256 && cbRet < cbData)
1347 {
1348 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | off);
1349 switch (cbData - cbRet)
1350 {
1351 case 1:
1352 ASMOutU8(PCI_CFG_DATA, pbData[cbRet]);
1353 cbRet += 1;
1354 break;
1355 case 2:
1356 ASMOutU16(PCI_CFG_DATA, RT_MAKE_U16(pbData[cbRet], pbData[cbRet + 1]));
1357 cbRet += 2;
1358 break;
1359 case 3:
1360 ASMOutU16(PCI_CFG_DATA, RT_MAKE_U16(pbData[cbRet], pbData[cbRet + 1]));
1361 ASMOutU8(PCI_CFG_DATA + 2, pbData[cbRet + 2]);
1362 cbRet += 3;
1363 break;
1364 default:
1365 ASMOutU32(PCI_CFG_DATA, RT_MAKE_U32_FROM_U8(pbData[cbRet], pbData[cbRet + 1],
1366 pbData[cbRet + 2], pbData[cbRet + 3]));
1367 cbRet += 4;
1368 break;
1369 }
1370 off += 4;
1371 }
1372
1373 return cbRet;
1374}
1375
1376
1377/**
1378 * NT 3.1 doesn't do PCI nor HalGetBusDataByOffset, this is our fallback.
1379 */
1380static ULONG NTAPI vgdrvNt31GetBusDataByOffset(BUS_DATA_TYPE enmBusDataType, ULONG idxBus, ULONG uSlot,
1381 void *pvData, ULONG offData, ULONG cbData)
1382{
1383 /*
1384 * Validate input a little bit.
1385 */
1386 RT_NOREF(enmBusDataType);
1387 Assert(idxBus <= 255);
1388 Assert(uSlot <= 255);
1389 Assert(offData <= 255);
1390 Assert(cbData > 0);
1391
1392 PCI_SLOT_NUMBER PciSlot;
1393 PciSlot.u.AsULONG = uSlot;
1394 uint32_t const idxAddrTop = UINT32_C(0x80000000)
1395 | (idxBus << 16)
1396 | (PciSlot.u.bits.DeviceNumber << 11)
1397 | (PciSlot.u.bits.FunctionNumber << 8);
1398
1399 /*
1400 * Read the header type.
1401 */
1402 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | (VBOX_PCI_HEADER_TYPE & ~3));
1403 uint8_t bHdrType = ASMInU8(PCI_CFG_DATA + (VBOX_PCI_HEADER_TYPE & 3));
1404 if (bHdrType == 0xff)
1405 return idxBus < 8 ? 2 : 0; /* No device here */
1406 if ( offData == VBOX_PCI_HEADER_TYPE
1407 && cbData == 1)
1408 {
1409 *(uint8_t *)pvData = bHdrType;
1410 /*Log("vgdrvNt31GetBusDataByOffset: PCI %#x/%#x -> %02x\n", idxAddrTop, offData, bHdrType);*/
1411 return 1;
1412 }
1413
1414 /*
1415 * Read the requested bytes.
1416 */
1417 uint8_t *pbData = (uint8_t *)pvData;
1418 uint32_t off = offData;
1419 uint32_t cbRet = 0;
1420
1421 /* Unaligned start. */
1422 if (off & 3)
1423 {
1424 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | (off & ~3));
1425 uint32_t uValue = ASMInU32(PCI_CFG_DATA);
1426 switch (off & 3)
1427 {
1428 case 1:
1429 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1430 if (cbRet >= cbData)
1431 break;
1432 RT_FALL_THRU();
1433 case 2:
1434 pbData[cbRet++] = (uint8_t)(uValue >> 16);
1435 if (cbRet >= cbData)
1436 break;
1437 RT_FALL_THRU();
1438 case 3:
1439 pbData[cbRet++] = (uint8_t)(uValue >> 24);
1440 break;
1441 }
1442 off = (off | 3) + 1;
1443 }
1444
1445 /* Bulk. */
1446 while (off < 256 && cbRet < cbData)
1447 {
1448 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | off);
1449 uint32_t uValue = ASMInU32(PCI_CFG_DATA);
1450 switch (cbData - cbRet)
1451 {
1452 case 1:
1453 pbData[cbRet++] = (uint8_t)uValue;
1454 break;
1455 case 2:
1456 pbData[cbRet++] = (uint8_t)uValue;
1457 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1458 break;
1459 case 3:
1460 pbData[cbRet++] = (uint8_t)uValue;
1461 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1462 pbData[cbRet++] = (uint8_t)(uValue >> 16);
1463 break;
1464 default:
1465 pbData[cbRet++] = (uint8_t)uValue;
1466 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1467 pbData[cbRet++] = (uint8_t)(uValue >> 16);
1468 pbData[cbRet++] = (uint8_t)(uValue >> 24);
1469 break;
1470 }
1471 off += 4;
1472 }
1473
1474 Log(("vgdrvNt31GetBusDataByOffset: PCI %#x/%#x -> %.*Rhxs\n", idxAddrTop, offData, cbRet, pvData));
1475 return cbRet;
1476}
1477
1478
1479/**
1480 * Helper function to handle the PCI device lookup.
1481 *
1482 * @returns NT status code.
1483 *
1484 * @param puBus Where to return the bus number on success.
1485 * @param pSlot Where to return the slot number on success.
1486 */
1487static NTSTATUS vgdrvNt4FindPciDevice(PULONG puBus, PPCI_SLOT_NUMBER pSlot)
1488{
1489 Log(("vgdrvNt4FindPciDevice\n"));
1490
1491 PCI_SLOT_NUMBER Slot;
1492 Slot.u.AsULONG = 0;
1493
1494 /* Scan each bus. */
1495 for (ULONG uBus = 0; uBus < PCI_MAX_BUSES; uBus++)
1496 {
1497 /* Scan each device. */
1498 for (ULONG idxDevice = 0; idxDevice < PCI_MAX_DEVICES; idxDevice++)
1499 {
1500 Slot.u.bits.DeviceNumber = idxDevice;
1501 Slot.u.bits.FunctionNumber = 0;
1502
1503 /* Check the device header. */
1504 uint8_t bHeaderType = 0xff;
1505 ULONG cbRet = g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, Slot.u.AsULONG,
1506 &bHeaderType, VBOX_PCI_HEADER_TYPE, sizeof(bHeaderType));
1507 if (cbRet == 0)
1508 break;
1509 if (cbRet == 2 || bHeaderType == 0xff)
1510 continue;
1511
1512 /* Scan functions. */
1513 uint32_t const cFunctionStep = bHeaderType & 0x80 ? 1 : 8;
1514 Log(("vgdrvNt4FindPciDevice: %#x:%#x cFunctionStep=%d bHeaderType=%#x\n", uBus, idxDevice, cFunctionStep, bHeaderType));
1515 for (ULONG idxFunction = 0; idxFunction < PCI_MAX_FUNCTION; idxFunction += cFunctionStep)
1516 {
1517 Slot.u.bits.FunctionNumber = idxFunction;
1518
1519 /* Read the vendor and device IDs of this device and compare with the VMMDev. */
1520 struct
1521 {
1522 uint16_t idVendor;
1523 uint16_t idDevice;
1524 } Buf = { PCI_INVALID_VENDORID, PCI_INVALID_VENDORID };
1525 cbRet = g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, Slot.u.AsULONG, &Buf, VBOX_PCI_VENDOR_ID, sizeof(Buf));
1526 if ( cbRet == sizeof(Buf)
1527 && Buf.idVendor == VMMDEV_VENDORID
1528 && Buf.idDevice == VMMDEV_DEVICEID)
1529 {
1530 /* Hooray, we've found it! */
1531 Log(("vgdrvNt4FindPciDevice: Device found! Bus=%#x Slot=%#u (dev %#x, fun %#x, rvd %#x)\n",
1532 uBus, Slot.u.AsULONG, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber, Slot.u.bits.Reserved));
1533
1534 *puBus = uBus;
1535 *pSlot = Slot;
1536 return STATUS_SUCCESS;
1537 }
1538 }
1539 }
1540 }
1541
1542 return STATUS_DEVICE_DOES_NOT_EXIST;
1543}
1544
1545
1546/**
1547 * Legacy helper function to create the device object.
1548 *
1549 * @returns NT status code.
1550 *
1551 * @param pDrvObj The driver object.
1552 * @param pRegPath The driver registry path.
1553 */
1554static NTSTATUS vgdrvNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1555{
1556 Log(("vgdrvNt4CreateDevice: pDrvObj=%p, pRegPath=%p\n", pDrvObj, pRegPath));
1557
1558 /*
1559 * Find our virtual PCI device
1560 */
1561 ULONG uBus;
1562 PCI_SLOT_NUMBER uSlot;
1563 NTSTATUS rc = vgdrvNt4FindPciDevice(&uBus, &uSlot);
1564 if (NT_ERROR(rc))
1565 {
1566 Log(("vgdrvNt4CreateDevice: Device not found!\n"));
1567 return rc;
1568 }
1569
1570 /*
1571 * Create device.
1572 */
1573 UNICODE_STRING DevName;
1574 RtlInitUnicodeString(&DevName, VBOXGUEST_DEVICE_NAME_NT);
1575 PDEVICE_OBJECT pDeviceObject = NULL;
1576 rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
1577 if (NT_SUCCESS(rc))
1578 {
1579 Log(("vgdrvNt4CreateDevice: Device created\n"));
1580
1581 UNICODE_STRING DosName;
1582 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
1583 rc = IoCreateSymbolicLink(&DosName, &DevName);
1584 if (NT_SUCCESS(rc))
1585 {
1586 Log(("vgdrvNt4CreateDevice: Symlink created\n"));
1587
1588 /*
1589 * Setup the device extension.
1590 */
1591 Log(("vgdrvNt4CreateDevice: Setting up device extension ...\n"));
1592 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
1593 int vrc = vgdrvNtInitDevExtFundament(pDevExt, pDeviceObject);
1594 if (RT_SUCCESS(vrc))
1595 {
1596 /* Store bus and slot number we've queried before. */
1597 pDevExt->uBus = uBus;
1598 pDevExt->uSlot = uSlot.u.AsULONG;
1599
1600 Log(("vgdrvNt4CreateDevice: Device extension created\n"));
1601
1602 /* Do the actual VBox init ... */
1603 rc = vgdrvNtSetupDevice(pDevExt, pDeviceObject, NULL /*pIrp*/, pDrvObj, pRegPath);
1604 if (NT_SUCCESS(rc))
1605 {
1606 Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x (success)\n", rc));
1607 return rc;
1608 }
1609
1610 /* bail out */
1611 vgdrvNtDeleteDevExtFundament(pDevExt);
1612 }
1613 IoDeleteSymbolicLink(&DosName);
1614 }
1615 else
1616 Log(("vgdrvNt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc));
1617 IoDeleteDevice(pDeviceObject);
1618 }
1619 else
1620 Log(("vgdrvNt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc));
1621 Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x\n", rc));
1622 return rc;
1623}
1624
1625#endif /* TARGET_NT4 */
1626
1627/**
1628 * Handle request from the Plug & Play subsystem.
1629 *
1630 * @returns NT status code
1631 * @param pDrvObj Driver object
1632 * @param pDevObj Device object
1633 *
1634 * @remarks Parts of this is duplicated in VBoxGuest-win-legacy.cpp.
1635 */
1636static NTSTATUS NTAPI vgdrvNtNt5PlusAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
1637{
1638 LogFlowFuncEnter();
1639
1640 /*
1641 * Create device.
1642 */
1643 UNICODE_STRING DevName;
1644 RtlInitUnicodeString(&DevName, VBOXGUEST_DEVICE_NAME_NT);
1645 PDEVICE_OBJECT pDeviceObject = NULL;
1646 NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
1647 if (NT_SUCCESS(rcNt))
1648 {
1649 /*
1650 * Create symbolic link (DOS devices).
1651 */
1652 UNICODE_STRING DosName;
1653 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
1654 rcNt = IoCreateSymbolicLink(&DosName, &DevName);
1655 if (NT_SUCCESS(rcNt))
1656 {
1657 /*
1658 * Setup the device extension.
1659 */
1660 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
1661 rcNt = vgdrvNtInitDevExtFundament(pDevExt, pDeviceObject);
1662 if (NT_SUCCESS(rcNt))
1663 {
1664 pDevExt->pNextLowerDriver = IoAttachDeviceToDeviceStack(pDeviceObject, pDevObj);
1665 if (pDevExt->pNextLowerDriver != NULL)
1666 {
1667 /* Ensure we are not called at elevated IRQL, even if our code isn't pagable any more. */
1668 pDeviceObject->Flags |= DO_POWER_PAGABLE;
1669
1670 /* Driver is ready now. */
1671 pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1672 LogFlowFunc(("Returning with rcNt=%#x (success)\n", rcNt));
1673 return rcNt;
1674 }
1675 LogFunc(("IoAttachDeviceToDeviceStack did not give a nextLowerDriver!\n"));
1676 rcNt = STATUS_DEVICE_NOT_CONNECTED;
1677 vgdrvNtDeleteDevExtFundament(pDevExt);
1678 }
1679
1680 IoDeleteSymbolicLink(&DosName);
1681 }
1682 else
1683 LogFunc(("IoCreateSymbolicLink failed with rcNt=%#x!\n", rcNt));
1684 IoDeleteDevice(pDeviceObject);
1685 }
1686 else
1687 LogFunc(("IoCreateDevice failed with rcNt=%#x!\n", rcNt));
1688
1689 LogFunc(("Returning with rcNt=%#x\n", rcNt));
1690 return rcNt;
1691}
1692
1693
1694/**
1695 * Irp completion routine for PnP Irps we send.
1696 *
1697 * @returns NT status code.
1698 * @param pDevObj Device object.
1699 * @param pIrp Request packet.
1700 * @param pEvent Semaphore.
1701 */
1702static NTSTATUS vgdrvNt5PlusPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
1703{
1704 RT_NOREF2(pDevObj, pIrp);
1705 KeSetEvent(pEvent, 0, FALSE);
1706 return STATUS_MORE_PROCESSING_REQUIRED;
1707}
1708
1709
1710/**
1711 * Helper to send a PnP IRP and wait until it's done.
1712 *
1713 * @returns NT status code.
1714 * @param pDevObj Device object.
1715 * @param pIrp Request packet.
1716 * @param fStrict When set, returns an error if the IRP gives an error.
1717 */
1718static NTSTATUS vgdrvNt5PlusPnPSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
1719{
1720 KEVENT Event;
1721
1722 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1723
1724 IoCopyCurrentIrpStackLocationToNext(pIrp);
1725 IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vgdrvNt5PlusPnpIrpComplete, &Event, TRUE, TRUE, TRUE);
1726
1727 NTSTATUS rcNt = IoCallDriver(pDevObj, pIrp);
1728 if (rcNt == STATUS_PENDING)
1729 {
1730 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1731 rcNt = pIrp->IoStatus.Status;
1732 }
1733
1734 if ( !fStrict
1735 && (rcNt == STATUS_NOT_SUPPORTED || rcNt == STATUS_INVALID_DEVICE_REQUEST))
1736 {
1737 rcNt = STATUS_SUCCESS;
1738 }
1739
1740 Log(("vgdrvNt5PlusPnPSendIrpSynchronously: Returning %#x\n", rcNt));
1741 return rcNt;
1742}
1743
1744
1745/**
1746 * Deletes the device hardware resources.
1747 *
1748 * Used during removal, stopping and legacy module unloading.
1749 *
1750 * @param pDevExt The device extension.
1751 */
1752static void vgdrvNtDeleteDeviceResources(PVBOXGUESTDEVEXTWIN pDevExt)
1753{
1754 if (pDevExt->pInterruptObject)
1755 {
1756 IoDisconnectInterrupt(pDevExt->pInterruptObject);
1757 pDevExt->pInterruptObject = NULL;
1758 }
1759 pDevExt->pPowerStateRequest = NULL; /* Will be deleted by the following call. */
1760 if (pDevExt->Core.uInitState == VBOXGUESTDEVEXT_INIT_STATE_RESOURCES)
1761 VGDrvCommonDeleteDevExtResources(&pDevExt->Core);
1762 vgdrvNtUnmapVMMDevMmioReq(pDevExt);
1763 vgdrvNtUnmapVMMDevMemory(pDevExt);
1764}
1765
1766
1767/**
1768 * Deletes the device extension fundament and unlinks the device
1769 *
1770 * Used during removal and legacy module unloading. Must have called
1771 * vgdrvNtDeleteDeviceResources.
1772 *
1773 * @param pDevObj Device object.
1774 * @param pDevExt The device extension.
1775 */
1776static void vgdrvNtDeleteDeviceFundamentAndUnlink(PDEVICE_OBJECT pDevObj, PVBOXGUESTDEVEXTWIN pDevExt)
1777{
1778 /*
1779 * Delete the remainder of the device extension.
1780 */
1781 vgdrvNtDeleteDevExtFundament(pDevExt);
1782
1783 /*
1784 * Delete the DOS symlink to the device and finally the device itself.
1785 */
1786 UNICODE_STRING DosName;
1787 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
1788 IoDeleteSymbolicLink(&DosName);
1789
1790 Log(("vgdrvNtDeleteDeviceFundamentAndUnlink: Deleting device ...\n"));
1791 IoDeleteDevice(pDevObj);
1792}
1793
1794
1795/**
1796 * Checks if the device is idle.
1797 * @returns STATUS_SUCCESS if idle, STATUS_UNSUCCESSFUL if busy.
1798 * @param pDevExt The device extension.
1799 * @param pszQueryNm The query name.
1800 */
1801static NTSTATUS vgdrvNtCheckIdle(PVBOXGUESTDEVEXTWIN pDevExt, const char *pszQueryNm)
1802{
1803 uint32_t cSessions = pDevExt->Core.cSessions;
1804 if (cSessions == 0)
1805 return STATUS_SUCCESS;
1806 LogRel(("vgdrvNtCheckIdle/%s: cSessions=%d\n", pszQueryNm, cSessions));
1807 return STATUS_UNSUCCESSFUL;
1808}
1809
1810
1811/**
1812 * PnP Request handler.
1813 *
1814 * @param pDevObj Device object.
1815 * @param pIrp Request packet.
1816 */
1817static NTSTATUS NTAPI vgdrvNtNt5PlusPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1818{
1819 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1820 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1821
1822#ifdef LOG_ENABLED
1823 static char const * const s_apszFnctName[] =
1824 {
1825 "IRP_MN_START_DEVICE",
1826 "IRP_MN_QUERY_REMOVE_DEVICE",
1827 "IRP_MN_REMOVE_DEVICE",
1828 "IRP_MN_CANCEL_REMOVE_DEVICE",
1829 "IRP_MN_STOP_DEVICE",
1830 "IRP_MN_QUERY_STOP_DEVICE",
1831 "IRP_MN_CANCEL_STOP_DEVICE",
1832 "IRP_MN_QUERY_DEVICE_RELATIONS",
1833 "IRP_MN_QUERY_INTERFACE",
1834 "IRP_MN_QUERY_CAPABILITIES",
1835 "IRP_MN_QUERY_RESOURCES",
1836 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
1837 "IRP_MN_QUERY_DEVICE_TEXT",
1838 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
1839 "IRP_MN_0xE",
1840 "IRP_MN_READ_CONFIG",
1841 "IRP_MN_WRITE_CONFIG",
1842 "IRP_MN_EJECT",
1843 "IRP_MN_SET_LOCK",
1844 "IRP_MN_QUERY_ID",
1845 "IRP_MN_QUERY_PNP_DEVICE_STATE",
1846 "IRP_MN_QUERY_BUS_INFORMATION",
1847 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
1848 "IRP_MN_SURPRISE_REMOVAL",
1849 };
1850 Log(("vgdrvNtNt5PlusPnP: MinorFunction: %s\n",
1851 pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName) ? s_apszFnctName[pStack->MinorFunction] : "Unknown"));
1852#endif
1853
1854 NTSTATUS rc = STATUS_SUCCESS;
1855 uint8_t bMinorFunction = pStack->MinorFunction;
1856 switch (bMinorFunction)
1857 {
1858 case IRP_MN_START_DEVICE:
1859 {
1860 Log(("vgdrvNtNt5PlusPnP: START_DEVICE\n"));
1861
1862 /* This must be handled first by the lower driver. */
1863 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
1864 if ( NT_SUCCESS(rc)
1865 && NT_SUCCESS(pIrp->IoStatus.Status))
1866 {
1867 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
1868 pStack->Parameters.StartDevice.AllocatedResources));
1869 if (pStack->Parameters.StartDevice.AllocatedResources)
1870 {
1871 rc = vgdrvNtSetupDevice(pDevExt, pDevObj, pIrp, NULL, NULL);
1872 if (NT_SUCCESS(rc))
1873 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: success\n"));
1874 else
1875 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: vgdrvNtSetupDevice failed: %#x\n", rc));
1876 }
1877 else
1878 {
1879 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
1880 pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL));
1881 rc = STATUS_UNSUCCESSFUL;
1882 }
1883 }
1884 else
1885 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: vgdrvNt5PlusPnPSendIrpSynchronously failed: %#x + %#x\n",
1886 rc, pIrp->IoStatus.Status));
1887
1888 pIrp->IoStatus.Status = rc;
1889 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1890 return rc;
1891 }
1892
1893
1894 /*
1895 * Sent before removing the device and/or driver.
1896 */
1897 case IRP_MN_QUERY_REMOVE_DEVICE:
1898 {
1899 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE\n"));
1900
1901 RTCritSectRwEnterExcl(&pDevExt->SessionCreateCritSect);
1902#ifdef VBOX_REBOOT_ON_UNINSTALL
1903 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
1904 rc = STATUS_UNSUCCESSFUL;
1905#endif
1906 if (NT_SUCCESS(rc))
1907 rc = vgdrvNtCheckIdle(pDevExt, "QUERY_REMOVE_DEVICE");
1908 if (NT_SUCCESS(rc))
1909 {
1910 pDevExt->enmDevState = VGDRVNTDEVSTATE_PENDINGREMOVE;
1911 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
1912
1913 /* This IRP passed down to lower driver. */
1914 pIrp->IoStatus.Status = STATUS_SUCCESS;
1915
1916 IoSkipCurrentIrpStackLocation(pIrp);
1917 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1918 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
1919
1920 /* We must not do anything the IRP after doing IoSkip & CallDriver
1921 since the driver below us will complete (or already have completed) the IRP.
1922 I.e. just return the status we got from IoCallDriver */
1923 }
1924 else
1925 {
1926 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
1927 pIrp->IoStatus.Status = rc;
1928 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1929 }
1930
1931 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Returning with rc = 0x%x\n", rc));
1932 return rc;
1933 }
1934
1935 /*
1936 * Cancels a pending remove, IRP_MN_QUERY_REMOVE_DEVICE.
1937 * We only have to revert the state.
1938 */
1939 case IRP_MN_CANCEL_REMOVE_DEVICE:
1940 {
1941 Log(("vgdrvNtNt5PlusPnP: CANCEL_REMOVE_DEVICE\n"));
1942
1943 /* This must be handled first by the lower driver. */
1944 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
1945 if ( NT_SUCCESS(rc)
1946 && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGREMOVE)
1947 {
1948 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
1949 pDevExt->enmDevState = pDevExt->enmPrevDevState;
1950 }
1951
1952 /* Complete the IRP. */
1953 pIrp->IoStatus.Status = rc;
1954 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1955 return rc;
1956 }
1957
1958 /*
1959 * We do nothing here actually, esp. since this request is not expected for VBoxGuest.
1960 * The cleanup will be done in IRP_MN_REMOVE_DEVICE, which follows this call.
1961 */
1962 case IRP_MN_SURPRISE_REMOVAL:
1963 {
1964 Log(("vgdrvNtNt5PlusPnP: IRP_MN_SURPRISE_REMOVAL\n"));
1965 pDevExt->enmDevState = VGDRVNTDEVSTATE_SURPRISEREMOVED;
1966 LogRel(("VBoxGuest: unexpected device removal\n"));
1967
1968 /* Pass to the lower driver. */
1969 pIrp->IoStatus.Status = STATUS_SUCCESS;
1970
1971 IoSkipCurrentIrpStackLocation(pIrp);
1972 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1973
1974 /* Do not complete the IRP. */
1975 return rc;
1976 }
1977
1978 /*
1979 * Device and/or driver removal. Destroy everything.
1980 */
1981 case IRP_MN_REMOVE_DEVICE:
1982 {
1983 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE\n"));
1984 pDevExt->enmDevState = VGDRVNTDEVSTATE_REMOVED;
1985
1986 /*
1987 * Disconnect interrupts and delete all hardware resources.
1988 * Note! This may already have been done if we're STOPPED already, if that's a possibility.
1989 */
1990 vgdrvNtDeleteDeviceResources(pDevExt);
1991
1992 /*
1993 * We need to send the remove down the stack before we detach, but we don't need
1994 * to wait for the completion of this operation (nor register a completion routine).
1995 */
1996 pIrp->IoStatus.Status = STATUS_SUCCESS;
1997
1998 IoSkipCurrentIrpStackLocation(pIrp);
1999 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2000 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
2001
2002 IoDetachDevice(pDevExt->pNextLowerDriver);
2003 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Removing device ...\n"));
2004
2005 /*
2006 * Delete the remainder of the device extension data, unlink it from the namespace and delete it.
2007 */
2008 vgdrvNtDeleteDeviceFundamentAndUnlink(pDevObj, pDevExt);
2009
2010 pDevObj = NULL; /* invalid */
2011 pDevExt = NULL; /* invalid */
2012
2013 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Device removed!\n"));
2014 return rc; /* Propagating rc from IoCallDriver. */
2015 }
2016
2017
2018 /*
2019 * Sent before stopping the device/driver to check whether it is okay to do so.
2020 */
2021 case IRP_MN_QUERY_STOP_DEVICE:
2022 {
2023 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE\n"));
2024 RTCritSectRwEnterExcl(&pDevExt->SessionCreateCritSect);
2025 rc = vgdrvNtCheckIdle(pDevExt, "QUERY_STOP_DEVICE");
2026 if (NT_SUCCESS(rc))
2027 {
2028 pDevExt->enmPrevDevState = pDevExt->enmDevState;
2029 pDevExt->enmDevState = VGDRVNTDEVSTATE_PENDINGSTOP;
2030 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
2031
2032 /* This IRP passed down to lower driver. */
2033 pIrp->IoStatus.Status = STATUS_SUCCESS;
2034
2035 IoSkipCurrentIrpStackLocation(pIrp);
2036
2037 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2038 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
2039
2040 /* we must not do anything with the IRP after doing IoSkip & CallDriver since the
2041 driver below us will complete (or already have completed) the IRP. I.e. just
2042 return the status we got from IoCallDriver. */
2043 }
2044 else
2045 {
2046 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
2047 pIrp->IoStatus.Status = rc;
2048 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2049 }
2050
2051 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE: Returning with rc = 0x%x\n", rc));
2052 return rc;
2053 }
2054
2055 /*
2056 * Cancels a pending remove, IRP_MN_QUERY_STOP_DEVICE.
2057 * We only have to revert the state.
2058 */
2059 case IRP_MN_CANCEL_STOP_DEVICE:
2060 {
2061 Log(("vgdrvNtNt5PlusPnP: CANCEL_STOP_DEVICE\n"));
2062
2063 /* This must be handled first by the lower driver. */
2064 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
2065 if ( NT_SUCCESS(rc)
2066 && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGSTOP)
2067 {
2068 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
2069 pDevExt->enmDevState = pDevExt->enmPrevDevState;
2070 }
2071
2072 /* Complete the IRP. */
2073 pIrp->IoStatus.Status = rc;
2074 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2075 return rc;
2076 }
2077
2078 /*
2079 * Stop the device.
2080 */
2081 case IRP_MN_STOP_DEVICE:
2082 {
2083 Log(("vgdrvNtNt5PlusPnP: STOP_DEVICE\n"));
2084 pDevExt->enmDevState = VGDRVNTDEVSTATE_STOPPED;
2085
2086 /*
2087 * Release the hardware resources.
2088 */
2089 vgdrvNtDeleteDeviceResources(pDevExt);
2090
2091 /*
2092 * Pass the request to the lower driver.
2093 */
2094 pIrp->IoStatus.Status = STATUS_SUCCESS;
2095 IoSkipCurrentIrpStackLocation(pIrp);
2096 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2097 Log(("vgdrvNtNt5PlusPnP: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
2098 return rc;
2099 }
2100
2101 default:
2102 {
2103 IoSkipCurrentIrpStackLocation(pIrp);
2104 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2105 Log(("vgdrvNtNt5PlusPnP: Unknown request %#x: Lower driver replied: %x\n", bMinorFunction, rc));
2106 return rc;
2107 }
2108 }
2109}
2110
2111
2112/**
2113 * Handle the power completion event.
2114 *
2115 * @returns NT status code.
2116 * @param pDevObj Targetted device object.
2117 * @param pIrp IO request packet.
2118 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
2119 */
2120static NTSTATUS vgdrvNtNt5PlusPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
2121{
2122#ifdef VBOX_STRICT
2123 RT_NOREF1(pDevObj);
2124 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pContext;
2125 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
2126
2127 Assert(pDevExt);
2128
2129 if (pIrpSp)
2130 {
2131 Assert(pIrpSp->MajorFunction == IRP_MJ_POWER);
2132 if (NT_SUCCESS(pIrp->IoStatus.Status))
2133 {
2134 switch (pIrpSp->MinorFunction)
2135 {
2136 case IRP_MN_SET_POWER:
2137 switch (pIrpSp->Parameters.Power.Type)
2138 {
2139 case DevicePowerState:
2140 switch (pIrpSp->Parameters.Power.State.DeviceState)
2141 {
2142 case PowerDeviceD0:
2143 break;
2144 default: /* Shut up MSC */
2145 break;
2146 }
2147 break;
2148 default: /* Shut up MSC */
2149 break;
2150 }
2151 break;
2152 }
2153 }
2154 }
2155#else
2156 RT_NOREF3(pDevObj, pIrp, pContext);
2157#endif
2158
2159 return STATUS_SUCCESS;
2160}
2161
2162
2163/**
2164 * Handle the Power requests.
2165 *
2166 * @returns NT status code
2167 * @param pDevObj device object
2168 * @param pIrp IRP
2169 */
2170static NTSTATUS NTAPI vgdrvNtNt5PlusPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2171{
2172 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2173 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2174 POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
2175 POWER_STATE PowerState = pStack->Parameters.Power.State;
2176 POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
2177
2178 Log(("vgdrvNtNt5PlusPower:\n"));
2179
2180 switch (pStack->MinorFunction)
2181 {
2182 case IRP_MN_SET_POWER:
2183 {
2184 Log(("vgdrvNtNt5PlusPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
2185 switch (enmPowerType)
2186 {
2187 case SystemPowerState:
2188 {
2189 Log(("vgdrvNtNt5PlusPower: SystemPowerState, action = %d, state = %d/%d\n",
2190 enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
2191
2192 switch (enmPowerAction)
2193 {
2194 case PowerActionSleep:
2195
2196 /* System now is in a working state. */
2197 if (PowerState.SystemState == PowerSystemWorking)
2198 {
2199 if ( pDevExt
2200 && pDevExt->enmLastSystemPowerAction == PowerActionHibernate)
2201 {
2202 Log(("vgdrvNtNt5PlusPower: Returning from hibernation!\n"));
2203 int rc = VGDrvCommonReinitDevExtAfterHibernation(&pDevExt->Core,
2204 vgdrvNtVersionToOSType(g_enmVGDrvNtVer));
2205 if (RT_FAILURE(rc))
2206 Log(("vgdrvNtNt5PlusPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
2207 }
2208 }
2209 break;
2210
2211 case PowerActionShutdownReset:
2212 {
2213 Log(("vgdrvNtNt5PlusPower: Power action reset!\n"));
2214
2215 /* Tell the VMM that we no longer support mouse pointer integration. */
2216 VMMDevReqMouseStatus *pReq = NULL;
2217 int vrc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus),
2218 VMMDevReq_SetMouseStatus);
2219 if (RT_SUCCESS(vrc))
2220 {
2221 pReq->mouseFeatures = 0;
2222 pReq->pointerXPos = 0;
2223 pReq->pointerYPos = 0;
2224
2225 vrc = VbglR0GRPerform(&pReq->header);
2226 if (RT_FAILURE(vrc))
2227 {
2228 Log(("vgdrvNtNt5PlusPower: error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
2229 }
2230
2231 VbglR0GRFree(&pReq->header);
2232 }
2233
2234 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
2235 * power action and would assert/crash when we already cleaned up all the stuff! */
2236 break;
2237 }
2238
2239 case PowerActionShutdown:
2240 case PowerActionShutdownOff:
2241 {
2242 Log(("vgdrvNtNt5PlusPower: Power action shutdown!\n"));
2243 if (PowerState.SystemState >= PowerSystemShutdown)
2244 {
2245 Log(("vgdrvNtNt5PlusPower: Telling the VMMDev to close the VM ...\n"));
2246
2247 VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
2248 int vrc = VERR_NOT_IMPLEMENTED;
2249 if (pReq)
2250 {
2251 pReq->header.requestType = VMMDevReq_SetPowerStatus;
2252 pReq->powerState = VMMDevPowerState_PowerOff;
2253
2254 vrc = VbglR0GRPerform(&pReq->header);
2255 }
2256 if (RT_FAILURE(vrc))
2257 Log(("vgdrvNtNt5PlusPower: Error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
2258
2259 /* No need to do cleanup here; at this point we should've been
2260 * turned off by VMMDev already! */
2261 }
2262 break;
2263 }
2264
2265 case PowerActionHibernate:
2266 Log(("vgdrvNtNt5PlusPower: Power action hibernate!\n"));
2267 break;
2268
2269 case PowerActionWarmEject:
2270 Log(("vgdrvNtNt5PlusPower: PowerActionWarmEject!\n"));
2271 break;
2272
2273 default:
2274 Log(("vgdrvNtNt5PlusPower: %d\n", enmPowerAction));
2275 break;
2276 }
2277
2278 /*
2279 * Save the current system power action for later use.
2280 * This becomes handy when we return from hibernation for example.
2281 */
2282 if (pDevExt)
2283 pDevExt->enmLastSystemPowerAction = enmPowerAction;
2284
2285 break;
2286 }
2287 default:
2288 break;
2289 }
2290 break;
2291 }
2292 default:
2293 break;
2294 }
2295
2296 /*
2297 * Whether we are completing or relaying this power IRP,
2298 * we must call PoStartNextPowerIrp.
2299 */
2300 g_pfnPoStartNextPowerIrp(pIrp);
2301
2302 /*
2303 * Send the IRP down the driver stack, using PoCallDriver
2304 * (not IoCallDriver, as for non-power irps).
2305 */
2306 IoCopyCurrentIrpStackLocationToNext(pIrp);
2307 IoSetCompletionRoutine(pIrp,
2308 vgdrvNtNt5PlusPowerComplete,
2309 (PVOID)pDevExt,
2310 TRUE,
2311 TRUE,
2312 TRUE);
2313 return g_pfnPoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2314}
2315
2316
2317/**
2318 * IRP_MJ_SYSTEM_CONTROL handler.
2319 *
2320 * @returns NT status code
2321 * @param pDevObj Device object.
2322 * @param pIrp IRP.
2323 */
2324static NTSTATUS NTAPI vgdrvNtNt5PlusSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2325{
2326 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2327
2328 LogFlowFuncEnter();
2329
2330 /* Always pass it on to the next driver. */
2331 IoSkipCurrentIrpStackLocation(pIrp);
2332
2333 return IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2334}
2335
2336
2337/**
2338 * Unload the driver.
2339 *
2340 * @param pDrvObj Driver object.
2341 */
2342static void NTAPI vgdrvNtUnload(PDRIVER_OBJECT pDrvObj)
2343{
2344 LogFlowFuncEnter();
2345
2346#ifdef TARGET_NT4
2347 /*
2348 * We need to destroy the device object here on NT4 and earlier.
2349 */
2350 PDEVICE_OBJECT pDevObj = pDrvObj->DeviceObject;
2351 if (pDevObj)
2352 {
2353 if (g_enmVGDrvNtVer <= VGDRVNTVER_WINNT4)
2354 {
2355 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2356 AssertPtr(pDevExt);
2357 AssertMsg(pDevExt->Core.uInitState == VBOXGUESTDEVEXT_INIT_STATE_RESOURCES,
2358 ("uInitState=%#x\n", pDevExt->Core.uInitState));
2359
2360 vgdrvNtDeleteDeviceResources(pDevExt);
2361 vgdrvNtDeleteDeviceFundamentAndUnlink(pDevObj, pDevExt);
2362 }
2363 }
2364#else /* !TARGET_NT4 */
2365 /*
2366 * On a PnP driver this routine will be called after IRP_MN_REMOVE_DEVICE
2367 * where we already did the cleanup, so don't do anything here (yet).
2368 */
2369 RT_NOREF1(pDrvObj);
2370#endif /* !TARGET_NT4 */
2371
2372 VGDrvCommonDestroyLoggers();
2373 RTR0Term();
2374
2375 /*
2376 * Finally deregister the bugcheck callback. Do it late to catch trouble in RTR0Term.
2377 */
2378 if (g_fBugCheckCallbackRegistered)
2379 {
2380 g_pfnKeDeregisterBugCheckCallback(&g_BugCheckCallbackRec);
2381 g_fBugCheckCallbackRegistered = false;
2382 }
2383}
2384
2385
2386/**
2387 * For simplifying request completion into a simple return statement, extended
2388 * version.
2389 *
2390 * @returns rcNt
2391 * @param rcNt The status code.
2392 * @param uInfo Extra info value.
2393 * @param pIrp The IRP.
2394 */
2395DECLINLINE(NTSTATUS) vgdrvNtCompleteRequestEx(NTSTATUS rcNt, ULONG_PTR uInfo, PIRP pIrp)
2396{
2397 pIrp->IoStatus.Status = rcNt;
2398 pIrp->IoStatus.Information = uInfo;
2399 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2400 return rcNt;
2401}
2402
2403
2404/**
2405 * For simplifying request completion into a simple return statement.
2406 *
2407 * @returns rcNt
2408 * @param rcNt The status code.
2409 * @param pIrp The IRP.
2410 */
2411DECLINLINE(NTSTATUS) vgdrvNtCompleteRequest(NTSTATUS rcNt, PIRP pIrp)
2412{
2413 return vgdrvNtCompleteRequestEx(rcNt, 0 /*uInfo*/, pIrp);
2414}
2415
2416
2417/**
2418 * Checks if NT authority rev 1 SID (SECURITY_NT_AUTHORITY).
2419 *
2420 * @returns true / false.
2421 * @param pSid The SID to check.
2422 */
2423DECLINLINE(bool) vgdrvNtIsSidNtAuth(struct _SID const *pSid)
2424{
2425 return pSid != NULL
2426 && pSid->Revision == 1
2427 && pSid->IdentifierAuthority.Value[5] == 5
2428 && pSid->IdentifierAuthority.Value[4] == 0
2429 && pSid->IdentifierAuthority.Value[3] == 0
2430 && pSid->IdentifierAuthority.Value[2] == 0
2431 && pSid->IdentifierAuthority.Value[1] == 0
2432 && pSid->IdentifierAuthority.Value[0] == 0;
2433}
2434
2435
2436/**
2437 * Matches SID with local system user (S-1-5-18 / SECURITY_LOCAL_SYSTEM_RID).
2438 */
2439DECLINLINE(bool) vgdrvNtIsSidLocalSystemUser(SID const *pSid)
2440{
2441 return vgdrvNtIsSidNtAuth(pSid)
2442 && pSid->SubAuthorityCount == 1
2443 && pSid->SubAuthority[0] == SECURITY_LOCAL_SYSTEM_RID;
2444}
2445
2446
2447/**
2448 * Matches SID with NT system admin user (S-1-5-*-500 / DOMAIN_USER_RID_ADMIN).
2449 */
2450DECLINLINE(bool) vgdrvNtIsSidAdminUser(SID const *pSid)
2451{
2452 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2453 return vgdrvNtIsSidNtAuth(pSid)
2454 && pSid->SubAuthorityCount >= 2
2455 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2456 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_USER_RID_ADMIN;
2457}
2458
2459
2460/**
2461 * Matches SID with NT system guest user (S-1-5-*-501 / DOMAIN_USER_RID_GUEST).
2462 */
2463DECLINLINE(bool) vgdrvNtIsSidGuestUser(SID const *pSid)
2464{
2465 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2466 return vgdrvNtIsSidNtAuth(pSid)
2467 && pSid->SubAuthorityCount >= 2
2468 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2469 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_USER_RID_GUEST;
2470}
2471
2472
2473/**
2474 * Matches SID with NT system admins group (S-1-5-32-544, S-1-5-*-512).
2475 */
2476DECLINLINE(bool) vgdrvNtIsSidAdminsGroup(SID const *pSid)
2477{
2478 return vgdrvNtIsSidNtAuth(pSid)
2479 && ( ( pSid->SubAuthorityCount == 2
2480 && pSid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID
2481 && pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_ADMINS)
2482#if 0
2483 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2484 || ( pSid->SubAuthorityCount >= 2
2485 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2486 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_GROUP_RID_ADMINS)
2487#endif
2488 );
2489}
2490
2491
2492/**
2493 * Matches SID with NT system users group (S-1-5-32-545, S-1-5-32-547, S-1-5-*-512).
2494 */
2495DECLINLINE(bool) vgdrvNtIsSidUsersGroup(SID const *pSid)
2496{
2497 return vgdrvNtIsSidNtAuth(pSid)
2498 && ( ( pSid->SubAuthorityCount == 2
2499 && pSid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID
2500 && ( pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_USERS
2501 || pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_POWER_USERS) )
2502#if 0
2503 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2504 || ( pSid->SubAuthorityCount >= 2
2505 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2506 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_GROUP_RID_USERS)
2507#endif
2508 );
2509}
2510
2511
2512/**
2513 * Matches SID with NT system guests group (S-1-5-32-546, S-1-5-*-512).
2514 */
2515DECLINLINE(bool) vgdrvNtIsSidGuestsGroup(SID const *pSid)
2516{
2517 return vgdrvNtIsSidNtAuth(pSid)
2518 && ( ( pSid->SubAuthorityCount == 2
2519 && pSid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID
2520 && pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_GUESTS)
2521#if 0
2522 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2523 || ( pSid->SubAuthorityCount >= 2
2524 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2525 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_GROUP_RID_GUESTS)
2526#endif
2527 );
2528}
2529
2530
2531/**
2532 * Checks if local authority rev 1 SID (SECURITY_LOCAL_SID_AUTHORITY).
2533 *
2534 * @returns true / false.
2535 * @param pSid The SID to check.
2536 */
2537DECLINLINE(bool) vgdrvNtIsSidLocalAuth(struct _SID const *pSid)
2538{
2539 return pSid != NULL
2540 && pSid->Revision == 1
2541 && pSid->IdentifierAuthority.Value[5] == 2
2542 && pSid->IdentifierAuthority.Value[4] == 0
2543 && pSid->IdentifierAuthority.Value[3] == 0
2544 && pSid->IdentifierAuthority.Value[2] == 0
2545 && pSid->IdentifierAuthority.Value[1] == 0
2546 && pSid->IdentifierAuthority.Value[0] == 0;
2547}
2548
2549
2550/**
2551 * Matches SID with console logon group (S-1-2-1 / SECURITY_LOCAL_LOGON_RID).
2552 */
2553DECLINLINE(bool) vgdrvNtIsSidConsoleLogonGroup(SID const *pSid)
2554{
2555 return vgdrvNtIsSidLocalAuth(pSid)
2556 && pSid->SubAuthorityCount == 1
2557 && pSid->SubAuthority[0] == SECURITY_LOCAL_LOGON_RID;
2558}
2559
2560
2561/**
2562 * Checks if mandatory label authority rev 1 SID (SECURITY_MANDATORY_LABEL_AUTHORITY).
2563 *
2564 * @returns true / false.
2565 * @param pSid The SID to check.
2566 */
2567DECLINLINE(bool) vgdrvNtIsSidMandatoryLabelAuth(struct _SID const *pSid)
2568{
2569 return pSid != NULL
2570 && pSid->Revision == 1
2571 && pSid->IdentifierAuthority.Value[5] == 16
2572 && pSid->IdentifierAuthority.Value[4] == 0
2573 && pSid->IdentifierAuthority.Value[3] == 0
2574 && pSid->IdentifierAuthority.Value[2] == 0
2575 && pSid->IdentifierAuthority.Value[1] == 0
2576 && pSid->IdentifierAuthority.Value[0] == 0;
2577}
2578
2579
2580#ifdef LOG_ENABLED
2581/** Format an SID for logging. */
2582static const char *vgdrvNtFormatSid(char *pszBuf, size_t cbBuf, struct _SID const *pSid)
2583{
2584 uint64_t uAuth = RT_MAKE_U64_FROM_U8(pSid->IdentifierAuthority.Value[5], pSid->IdentifierAuthority.Value[4],
2585 pSid->IdentifierAuthority.Value[3], pSid->IdentifierAuthority.Value[2],
2586 pSid->IdentifierAuthority.Value[1], pSid->IdentifierAuthority.Value[0],
2587 0, 0);
2588 ssize_t offCur = RTStrPrintf2(pszBuf, cbBuf, "S-%u-%RU64", pSid->Revision, uAuth);
2589 ULONG const *puSubAuth = &pSid->SubAuthority[0];
2590 unsigned cSubAuths = pSid->SubAuthorityCount;
2591 while (cSubAuths > 0 && (size_t)offCur < cbBuf)
2592 {
2593 ssize_t cchThis = RTStrPrintf2(&pszBuf[offCur], cbBuf - (size_t)offCur, "-%u", *puSubAuth);
2594 if (cchThis > 0)
2595 {
2596 offCur += cchThis;
2597 puSubAuth++;
2598 cSubAuths--;
2599 }
2600 else
2601 {
2602 Assert(cbBuf >= 5);
2603 pszBuf[cbBuf - 4] = '.';
2604 pszBuf[cbBuf - 3] = '.';
2605 pszBuf[cbBuf - 2] = '.';
2606 pszBuf[cbBuf - 1] = '\0';
2607 break;
2608 }
2609 }
2610 return pszBuf;
2611}
2612#endif
2613
2614
2615/**
2616 * Calculate requestor flags for the current process.
2617 *
2618 * ASSUMES vgdrvNtCreate is executed in the context of the process and thread
2619 * doing the NtOpenFile call.
2620 *
2621 * @returns VMMDEV_REQUESTOR_XXX
2622 */
2623static uint32_t vgdrvNtCalcRequestorFlags(void)
2624{
2625 uint32_t fRequestor = VMMDEV_REQUESTOR_USERMODE
2626 | VMMDEV_REQUESTOR_USR_NOT_GIVEN
2627 | VMMDEV_REQUESTOR_CON_DONT_KNOW
2628 | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN
2629 | VMMDEV_REQUESTOR_NO_USER_DEVICE;
2630 HANDLE hToken = NULL;
2631 NTSTATUS rcNt = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken);
2632 if (NT_SUCCESS(rcNt))
2633 {
2634 union
2635 {
2636 TOKEN_USER CurUser;
2637 TOKEN_GROUPS CurGroups;
2638 uint8_t abPadding[256];
2639 } Buf;
2640#ifdef LOG_ENABLED
2641 char szSid[200];
2642#endif
2643
2644 /*
2645 * Get the user SID and see if it's a standard one.
2646 */
2647 RT_ZERO(Buf.CurUser);
2648 ULONG cbReturned = 0;
2649 rcNt = ZwQueryInformationToken(hToken, TokenUser, &Buf.CurUser, sizeof(Buf), &cbReturned);
2650 if (NT_SUCCESS(rcNt))
2651 {
2652 struct _SID const *pSid = (struct _SID const *)Buf.CurUser.User.Sid;
2653 Log5(("vgdrvNtCalcRequestorFlags: TokenUser: %#010x %s\n",
2654 Buf.CurUser.User.Attributes, vgdrvNtFormatSid(szSid, sizeof(szSid), pSid)));
2655
2656 if (vgdrvNtIsSidLocalSystemUser(pSid))
2657 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_SYSTEM;
2658 else if (vgdrvNtIsSidAdminUser(pSid))
2659 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_ROOT;
2660 else if (vgdrvNtIsSidGuestUser(pSid))
2661 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_GUEST;
2662 }
2663 else
2664 LogRel(("vgdrvNtCalcRequestorFlags: TokenUser query failed: %#x\n", rcNt));
2665
2666 /*
2667 * Get the groups.
2668 */
2669 TOKEN_GROUPS *pCurGroupsFree = NULL;
2670 TOKEN_GROUPS *pCurGroups = &Buf.CurGroups;
2671 uint32_t cbCurGroups = sizeof(Buf);
2672 cbReturned = 0;
2673 RT_ZERO(Buf);
2674 rcNt = ZwQueryInformationToken(hToken, TokenGroups, pCurGroups, cbCurGroups, &cbReturned);
2675 if (rcNt == STATUS_BUFFER_TOO_SMALL)
2676 {
2677 uint32_t cTries = 8;
2678 do
2679 {
2680 RTMemTmpFree(pCurGroupsFree);
2681 if (cbCurGroups < cbReturned)
2682 cbCurGroups = RT_ALIGN_32(cbCurGroups + 32, 64);
2683 else
2684 cbCurGroups += 64;
2685 pCurGroupsFree = pCurGroups = (TOKEN_GROUPS *)RTMemTmpAllocZ(cbCurGroups);
2686 if (pCurGroupsFree)
2687 rcNt = ZwQueryInformationToken(hToken, TokenGroups, pCurGroups, cbCurGroups, &cbReturned);
2688 else
2689 rcNt = STATUS_NO_MEMORY;
2690 } while (rcNt == STATUS_BUFFER_TOO_SMALL && cTries-- > 0);
2691 }
2692 if (NT_SUCCESS(rcNt))
2693 {
2694 bool fGuestsMember = false;
2695 bool fUsersMember = false;
2696 if (g_enmVGDrvNtVer >= VGDRVNTVER_WIN7)
2697 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_CON_MASK) | VMMDEV_REQUESTOR_CON_NO;
2698
2699 for (uint32_t iGrp = 0; iGrp < pCurGroups->GroupCount; iGrp++)
2700 {
2701 uint32_t const fAttribs = pCurGroups->Groups[iGrp].Attributes;
2702 struct _SID const *pSid = (struct _SID const *)pCurGroups->Groups[iGrp].Sid;
2703 Log5(("vgdrvNtCalcRequestorFlags: TokenGroups[%u]: %#10x %s\n",
2704 iGrp, fAttribs, vgdrvNtFormatSid(szSid, sizeof(szSid), pSid)));
2705
2706 if ( (fAttribs & SE_GROUP_INTEGRITY_ENABLED)
2707 && vgdrvNtIsSidMandatoryLabelAuth(pSid)
2708 && pSid->SubAuthorityCount == 1
2709 && (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_NOT_GIVEN)
2710 {
2711 fRequestor &= ~VMMDEV_REQUESTOR_TRUST_MASK;
2712 if (pSid->SubAuthority[0] < SECURITY_MANDATORY_LOW_RID)
2713 fRequestor |= VMMDEV_REQUESTOR_TRUST_UNTRUSTED;
2714 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_MEDIUM_RID)
2715 fRequestor |= VMMDEV_REQUESTOR_TRUST_LOW;
2716 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_MEDIUM_PLUS_RID)
2717 fRequestor |= VMMDEV_REQUESTOR_TRUST_MEDIUM;
2718 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_HIGH_RID)
2719 fRequestor |= VMMDEV_REQUESTOR_TRUST_MEDIUM_PLUS;
2720 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_SYSTEM_RID)
2721 fRequestor |= VMMDEV_REQUESTOR_TRUST_HIGH;
2722 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_PROTECTED_PROCESS_RID)
2723 fRequestor |= VMMDEV_REQUESTOR_TRUST_SYSTEM;
2724 else
2725 fRequestor |= VMMDEV_REQUESTOR_TRUST_PROTECTED;
2726 Log5(("vgdrvNtCalcRequestorFlags: mandatory label %u: => %#x\n", pSid->SubAuthority[0], fRequestor));
2727 }
2728 else if ( (fAttribs & (SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_USE_FOR_DENY_ONLY))
2729 == (SE_GROUP_ENABLED | SE_GROUP_MANDATORY)
2730 && vgdrvNtIsSidConsoleLogonGroup(pSid))
2731 {
2732 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_CON_MASK) | VMMDEV_REQUESTOR_CON_YES;
2733 Log5(("vgdrvNtCalcRequestorFlags: console: => %#x\n", fRequestor));
2734 }
2735 else if ( (fAttribs & (SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_USE_FOR_DENY_ONLY))
2736 == (SE_GROUP_ENABLED | SE_GROUP_MANDATORY)
2737 && vgdrvNtIsSidNtAuth(pSid))
2738 {
2739 if (vgdrvNtIsSidAdminsGroup(pSid))
2740 {
2741 fRequestor |= VMMDEV_REQUESTOR_GRP_WHEEL;
2742 Log5(("vgdrvNtCalcRequestorFlags: admins group: => %#x\n", fRequestor));
2743 }
2744 else if (vgdrvNtIsSidUsersGroup(pSid))
2745 {
2746 Log5(("vgdrvNtCalcRequestorFlags: users group\n"));
2747 fUsersMember = true;
2748 }
2749 else if (vgdrvNtIsSidGuestsGroup(pSid))
2750 {
2751 Log5(("vgdrvNtCalcRequestorFlags: guests group\n"));
2752 fGuestsMember = true;
2753 }
2754 }
2755 }
2756 if ((fRequestor & VMMDEV_REQUESTOR_USR_MASK) == VMMDEV_REQUESTOR_USR_NOT_GIVEN)
2757 {
2758 if (fUsersMember)
2759 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_USER;
2760 else if (fGuestsMember)
2761 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_GUEST;
2762 }
2763 }
2764 else
2765 LogRel(("vgdrvNtCalcRequestorFlags: TokenGroups query failed: %#x\n", rcNt));
2766
2767 RTMemTmpFree(pCurGroupsFree);
2768 ZwClose(hToken);
2769
2770 /*
2771 * Determine whether we should set VMMDEV_REQUESTOR_USER_DEVICE or not.
2772 *
2773 * The purpose here is to differentiate VBoxService accesses
2774 * from VBoxTray and VBoxControl, as VBoxService should be allowed to
2775 * do more than the latter two. VBoxService normally runs under the
2776 * system account which is easily detected, but for debugging and
2777 * similar purposes we also allow an elevated admin to run it as well.
2778 */
2779 if ( (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_UNTRUSTED /* general paranoia wrt system account */
2780 || (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_LOW /* ditto */
2781 || (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_MEDIUM /* ditto */
2782 || !( (fRequestor & VMMDEV_REQUESTOR_USR_MASK) == VMMDEV_REQUESTOR_USR_SYSTEM
2783 || ( ( (fRequestor & VMMDEV_REQUESTOR_GRP_WHEEL)
2784 || (fRequestor & VMMDEV_REQUESTOR_USR_MASK) == VMMDEV_REQUESTOR_USR_ROOT)
2785 && ( (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) >= VMMDEV_REQUESTOR_TRUST_HIGH
2786 || (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_NOT_GIVEN)) ))
2787 fRequestor |= VMMDEV_REQUESTOR_USER_DEVICE;
2788 }
2789 else
2790 {
2791 LogRel(("vgdrvNtCalcRequestorFlags: NtOpenProcessToken query failed: %#x\n", rcNt));
2792 fRequestor |= VMMDEV_REQUESTOR_USER_DEVICE;
2793 }
2794
2795 Log5(("vgdrvNtCalcRequestorFlags: returns %#x\n", fRequestor));
2796 return fRequestor;
2797}
2798
2799
2800/**
2801 * Create (i.e. Open) file entry point.
2802 *
2803 * @param pDevObj Device object.
2804 * @param pIrp Request packet.
2805 */
2806static NTSTATUS NTAPI vgdrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2807{
2808 Log(("vgdrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
2809 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2810 PFILE_OBJECT pFileObj = pStack->FileObject;
2811 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2812
2813 Assert(pFileObj->FsContext == NULL);
2814
2815 /*
2816 * We are not remotely similar to a directory...
2817 */
2818 NTSTATUS rcNt;
2819 if (!(pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE))
2820 {
2821 /*
2822 * Check the device state. We enter the critsect in shared mode to
2823 * prevent race with PnP system requests checking whether we're idle.
2824 */
2825 RTCritSectRwEnterShared(&pDevExt->SessionCreateCritSect);
2826 VGDRVNTDEVSTATE const enmDevState = pDevExt->enmDevState;
2827 if (enmDevState == VGDRVNTDEVSTATE_OPERATIONAL)
2828 {
2829 /*
2830 * Create a client session.
2831 */
2832 int rc;
2833 PVBOXGUESTSESSION pSession;
2834 if (pIrp->RequestorMode == KernelMode)
2835 rc = VGDrvCommonCreateKernelSession(&pDevExt->Core, &pSession);
2836 else
2837 rc = VGDrvCommonCreateUserSession(&pDevExt->Core, vgdrvNtCalcRequestorFlags(), &pSession);
2838 RTCritSectRwLeaveShared(&pDevExt->SessionCreateCritSect);
2839 if (RT_SUCCESS(rc))
2840 {
2841 pFileObj->FsContext = pSession;
2842 Log(("vgdrvNtCreate: Successfully created %s session %p (fRequestor=%#x)\n",
2843 pIrp->RequestorMode == KernelMode ? "kernel" : "user", pSession, pSession->fRequestor));
2844
2845 return vgdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
2846 }
2847
2848 /* Note. the IoStatus is completely ignored on error. */
2849 Log(("vgdrvNtCreate: Failed to create session: rc=%Rrc\n", rc));
2850 if (rc == VERR_NO_MEMORY)
2851 rcNt = STATUS_NO_MEMORY;
2852 else
2853 rcNt = STATUS_UNSUCCESSFUL;
2854 }
2855 else
2856 {
2857 RTCritSectRwLeaveShared(&pDevExt->SessionCreateCritSect);
2858 LogFlow(("vgdrvNtCreate: Failed. Device is not in 'working' state: %d\n", enmDevState));
2859 rcNt = STATUS_DEVICE_NOT_READY;
2860 }
2861 }
2862 else
2863 {
2864 LogFlow(("vgdrvNtCreate: Failed. FILE_DIRECTORY_FILE set\n"));
2865 rcNt = STATUS_NOT_A_DIRECTORY;
2866 }
2867 return vgdrvNtCompleteRequest(rcNt, pIrp);
2868}
2869
2870
2871/**
2872 * Close file entry point.
2873 *
2874 * @param pDevObj Device object.
2875 * @param pIrp Request packet.
2876 */
2877static NTSTATUS NTAPI vgdrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2878{
2879 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2880 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2881 PFILE_OBJECT pFileObj = pStack->FileObject;
2882
2883 LogFlowFunc(("pDevExt=0x%p, pFileObj=0x%p, FsContext=0x%p\n", pDevExt, pFileObj, pFileObj->FsContext));
2884
2885#ifdef VBOX_WITH_HGCM
2886 /* Close both, R0 and R3 sessions. */
2887 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFileObj->FsContext;
2888 if (pSession)
2889 VGDrvCommonCloseSession(&pDevExt->Core, pSession);
2890#endif
2891
2892 pFileObj->FsContext = NULL;
2893 pIrp->IoStatus.Information = 0;
2894 pIrp->IoStatus.Status = STATUS_SUCCESS;
2895 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2896
2897 return STATUS_SUCCESS;
2898}
2899
2900
2901/**
2902 * Device I/O Control entry point.
2903 *
2904 * @param pDevObj Device object.
2905 * @param pIrp Request packet.
2906 */
2907NTSTATUS NTAPI vgdrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2908{
2909 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2910 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2911 PVBOXGUESTSESSION pSession = pStack->FileObject ? (PVBOXGUESTSESSION)pStack->FileObject->FsContext : NULL;
2912
2913 if (!RT_VALID_PTR(pSession))
2914 return vgdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
2915
2916#if 0 /* No fast I/O controls defined yet. */
2917 /*
2918 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
2919 * the session and iCmd, and does not return anything.
2920 */
2921 if (pSession->fUnrestricted)
2922 {
2923 ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
2924 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
2925 || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
2926 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
2927 {
2928 int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
2929
2930 /* Complete the I/O request. */
2931 supdrvSessionRelease(pSession);
2932 return vgdrvNtCompleteRequest(RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER, pIrp);
2933 }
2934 }
2935#endif
2936
2937 return vgdrvNtDeviceControlSlow(&pDevExt->Core, pSession, pIrp, pStack);
2938}
2939
2940
2941/**
2942 * Device I/O Control entry point.
2943 *
2944 * @param pDevExt The device extension.
2945 * @param pSession The session.
2946 * @param pIrp Request packet.
2947 * @param pStack The request stack pointer.
2948 */
2949static NTSTATUS vgdrvNtDeviceControlSlow(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
2950 PIRP pIrp, PIO_STACK_LOCATION pStack)
2951{
2952 NTSTATUS rcNt;
2953 uint32_t cbOut = 0;
2954 int rc = 0;
2955 Log2(("vgdrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
2956 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
2957 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
2958 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
2959
2960#if 0 /*def RT_ARCH_AMD64*/
2961 /* Don't allow 32-bit processes to do any I/O controls. */
2962 if (!IoIs32bitProcess(pIrp))
2963#endif
2964 {
2965 /* Verify that it's a buffered CTL. */
2966 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
2967 {
2968 /* Verify that the sizes in the request header are correct. */
2969 PVBGLREQHDR pHdr = (PVBGLREQHDR)pIrp->AssociatedIrp.SystemBuffer;
2970 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
2971 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
2972 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
2973 {
2974 /* Zero extra output bytes to make sure we don't leak anything. */
2975 if (pHdr->cbIn < pHdr->cbOut)
2976 RtlZeroMemory((uint8_t *)pHdr + pHdr->cbIn, pHdr->cbOut - pHdr->cbIn);
2977
2978 /*
2979 * Do the job.
2980 */
2981 rc = VGDrvCommonIoCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr,
2982 RT_MAX(pHdr->cbIn, pHdr->cbOut));
2983 if (RT_SUCCESS(rc))
2984 {
2985 rcNt = STATUS_SUCCESS;
2986 cbOut = pHdr->cbOut;
2987 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
2988 {
2989 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
2990 LogRel(("vgdrvNtDeviceControlSlow: too much output! %#x > %#x; uCmd=%#x!\n",
2991 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
2992 }
2993
2994 /* If IDC successful disconnect request, we must set the context pointer to NULL. */
2995 if ( pStack->Parameters.DeviceIoControl.IoControlCode == VBGL_IOCTL_IDC_DISCONNECT
2996 && RT_SUCCESS(pHdr->rc))
2997 pStack->FileObject->FsContext = NULL;
2998 }
2999 else if (rc == VERR_NOT_SUPPORTED)
3000 rcNt = STATUS_NOT_SUPPORTED;
3001 else
3002 rcNt = STATUS_INVALID_PARAMETER;
3003 Log2(("vgdrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
3004 }
3005 else
3006 {
3007 Log(("vgdrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
3008 pStack->Parameters.DeviceIoControl.IoControlCode,
3009 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
3010 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
3011 pStack->Parameters.DeviceIoControl.InputBufferLength,
3012 pStack->Parameters.DeviceIoControl.OutputBufferLength));
3013 rcNt = STATUS_INVALID_PARAMETER;
3014 }
3015 }
3016 else
3017 {
3018 Log(("vgdrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
3019 pStack->Parameters.DeviceIoControl.IoControlCode));
3020 rcNt = STATUS_NOT_SUPPORTED;
3021 }
3022 }
3023#if 0 /*def RT_ARCH_AMD64*/
3024 else
3025 {
3026 Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
3027 rcNt = STATUS_NOT_SUPPORTED;
3028 }
3029#endif
3030
3031 return vgdrvNtCompleteRequestEx(rcNt, cbOut, pIrp);
3032}
3033
3034
3035/**
3036 * Internal Device I/O Control entry point (for IDC).
3037 *
3038 * @param pDevObj Device object.
3039 * @param pIrp Request packet.
3040 */
3041static NTSTATUS NTAPI vgdrvNtInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
3042{
3043 /* Currently no special code here. */
3044 return vgdrvNtDeviceControl(pDevObj, pIrp);
3045}
3046
3047
3048/**
3049 * IRP_MJ_SHUTDOWN handler.
3050 *
3051 * @returns NT status code
3052 * @param pDevObj Device object.
3053 * @param pIrp IRP.
3054 */
3055static NTSTATUS NTAPI vgdrvNtShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
3056{
3057 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
3058 LogFlowFuncEnter();
3059
3060 VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
3061 if (pReq)
3062 {
3063 pReq->header.requestType = VMMDevReq_SetPowerStatus;
3064 pReq->powerState = VMMDevPowerState_PowerOff;
3065
3066 int rc = VbglR0GRPerform(&pReq->header);
3067 if (RT_FAILURE(rc))
3068 LogFunc(("Error performing request to VMMDev, rc=%Rrc\n", rc));
3069 }
3070
3071 /* just in case, since we shouldn't normally get here. */
3072 pIrp->IoStatus.Information = 0;
3073 pIrp->IoStatus.Status = STATUS_SUCCESS;
3074 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
3075 return STATUS_SUCCESS;
3076}
3077
3078
3079/**
3080 * Stub function for functions we don't implemented.
3081 *
3082 * @returns STATUS_NOT_SUPPORTED
3083 * @param pDevObj Device object.
3084 * @param pIrp IRP.
3085 */
3086static NTSTATUS vgdrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
3087{
3088 RT_NOREF1(pDevObj);
3089 LogFlowFuncEnter();
3090
3091 pIrp->IoStatus.Information = 0;
3092 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
3093 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
3094
3095 return STATUS_NOT_SUPPORTED;
3096}
3097
3098
3099/**
3100 * Bug check callback (KBUGCHECK_CALLBACK_ROUTINE).
3101 *
3102 * This adds a log entry on the host, in case Hyper-V isn't active or the guest
3103 * is too old for reporting it itself via the crash MSRs.
3104 *
3105 * @param pvBuffer Not used.
3106 * @param cbBuffer Not used.
3107 */
3108static VOID NTAPI vgdrvNtBugCheckCallback(PVOID pvBuffer, ULONG cbBuffer)
3109{
3110 if (g_pauKiBugCheckData)
3111 {
3112 RTLogBackdoorPrintf("VBoxGuest: BugCheck! P0=%#zx P1=%#zx P2=%#zx P3=%#zx P4=%#zx\n", g_pauKiBugCheckData[0],
3113 g_pauKiBugCheckData[1], g_pauKiBugCheckData[2], g_pauKiBugCheckData[3], g_pauKiBugCheckData[4]);
3114
3115 VMMDevReqNtBugCheck *pReq = NULL;
3116 int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_NtBugCheck);
3117 if (RT_SUCCESS(rc))
3118 {
3119 pReq->uBugCheck = g_pauKiBugCheckData[0];
3120 pReq->auParameters[0] = g_pauKiBugCheckData[1];
3121 pReq->auParameters[1] = g_pauKiBugCheckData[2];
3122 pReq->auParameters[2] = g_pauKiBugCheckData[3];
3123 pReq->auParameters[3] = g_pauKiBugCheckData[4];
3124 VbglR0GRPerform(&pReq->header);
3125 VbglR0GRFree(&pReq->header);
3126 }
3127 }
3128 else
3129 {
3130 RTLogBackdoorPrintf("VBoxGuest: BugCheck!\n");
3131
3132 VMMDevRequestHeader *pReqHdr = NULL;
3133 int rc = VbglR0GRAlloc(&pReqHdr, sizeof(*pReqHdr), VMMDevReq_NtBugCheck);
3134 if (RT_SUCCESS(rc))
3135 {
3136 VbglR0GRPerform(pReqHdr);
3137 VbglR0GRFree(pReqHdr);
3138 }
3139 }
3140
3141 RT_NOREF(pvBuffer, cbBuffer);
3142}
3143
3144
3145/**
3146 * Sets the mouse notification callback.
3147 *
3148 * @returns VBox status code.
3149 * @param pDevExt Pointer to the device extension.
3150 * @param pNotify Pointer to the mouse notify struct.
3151 */
3152int VGDrvNativeSetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, PVBGLIOCSETMOUSENOTIFYCALLBACK pNotify)
3153{
3154 PVBOXGUESTDEVEXTWIN pDevExtWin = (PVBOXGUESTDEVEXTWIN)pDevExt;
3155 /* we need a lock here to avoid concurrency with the set event functionality */
3156 KIRQL OldIrql;
3157 KeAcquireSpinLock(&pDevExtWin->MouseEventAccessSpinLock, &OldIrql);
3158 pDevExtWin->Core.pfnMouseNotifyCallback = pNotify->u.In.pfnNotify;
3159 pDevExtWin->Core.pvMouseNotifyCallbackArg = pNotify->u.In.pvUser;
3160 KeReleaseSpinLock(&pDevExtWin->MouseEventAccessSpinLock, OldIrql);
3161 return VINF_SUCCESS;
3162}
3163
3164
3165/**
3166 * DPC handler.
3167 *
3168 * @param pDPC DPC descriptor.
3169 * @param pDevObj Device object.
3170 * @param pIrp Interrupt request packet.
3171 * @param pContext Context specific pointer.
3172 */
3173static void NTAPI vgdrvNtDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext)
3174{
3175 RT_NOREF3(pDPC, pIrp, pContext);
3176 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
3177 Log3Func(("pDevExt=0x%p\n", pDevExt));
3178
3179 /* Test & reset the counter. */
3180 if (ASMAtomicXchgU32(&pDevExt->Core.u32MousePosChangedSeq, 0))
3181 {
3182 /* we need a lock here to avoid concurrency with the set event ioctl handler thread,
3183 * i.e. to prevent the event from destroyed while we're using it */
3184 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
3185 KeAcquireSpinLockAtDpcLevel(&pDevExt->MouseEventAccessSpinLock);
3186
3187 if (pDevExt->Core.pfnMouseNotifyCallback)
3188 pDevExt->Core.pfnMouseNotifyCallback(pDevExt->Core.pvMouseNotifyCallbackArg);
3189
3190 KeReleaseSpinLockFromDpcLevel(&pDevExt->MouseEventAccessSpinLock);
3191 }
3192
3193 /* Process the wake-up list we were asked by the scheduling a DPC
3194 * in vgdrvNtIsrHandler(). */
3195 VGDrvCommonWaitDoWakeUps(&pDevExt->Core);
3196}
3197
3198
3199/**
3200 * ISR handler.
3201 *
3202 * @return BOOLEAN Indicates whether the IRQ came from us (TRUE) or not (FALSE).
3203 * @param pInterrupt Interrupt that was triggered.
3204 * @param pServiceContext Context specific pointer.
3205 */
3206static BOOLEAN NTAPI vgdrvNtIsrHandler(PKINTERRUPT pInterrupt, PVOID pServiceContext)
3207{
3208 RT_NOREF1(pInterrupt);
3209 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pServiceContext;
3210 if (pDevExt == NULL)
3211 return FALSE;
3212
3213 /*Log3Func(("pDevExt=0x%p, pVMMDevMemory=0x%p\n", pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL));*/
3214
3215 /* Enter the common ISR routine and do the actual work. */
3216 BOOLEAN fIRQTaken = VGDrvCommonISR(&pDevExt->Core);
3217
3218 /* If we need to wake up some events we do that in a DPC to make
3219 * sure we're called at the right IRQL. */
3220 if (fIRQTaken)
3221 {
3222 Log3Func(("IRQ was taken! pInterrupt=0x%p, pDevExt=0x%p\n", pInterrupt, pDevExt));
3223 if (ASMAtomicUoReadU32( &pDevExt->Core.u32MousePosChangedSeq)
3224 || !RTListIsEmpty(&pDevExt->Core.WakeUpList))
3225 {
3226 Log3Func(("Requesting DPC...\n"));
3227 IoRequestDpc(pDevExt->pDeviceObject, NULL /*pIrp*/, NULL /*pvContext*/);
3228 }
3229 }
3230 return fIRQTaken;
3231}
3232
3233
3234void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
3235{
3236 NOREF(pDevExt);
3237 /* nothing to do here - i.e. since we can not KeSetEvent from ISR level,
3238 * we rely on the pDevExt->u32MousePosChangedSeq to be set to a non-zero value on a mouse event
3239 * and queue the DPC in our ISR routine in that case doing KeSetEvent from the DPC routine */
3240}
3241
3242
3243/**
3244 * Hook for handling OS specfic options from the host.
3245 *
3246 * @returns true if handled, false if not.
3247 * @param pDevExt The device extension.
3248 * @param pszName The option name.
3249 * @param pszValue The option value.
3250 */
3251bool VGDrvNativeProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue)
3252{
3253 RT_NOREF(pDevExt); RT_NOREF(pszName); RT_NOREF(pszValue);
3254 return false;
3255}
3256
3257
3258/**
3259 * Implements RTL_QUERY_REGISTRY_ROUTINE for enumerating our registry key.
3260 */
3261static NTSTATUS NTAPI vgdrvNtRegistryEnumCallback(PWSTR pwszValueName, ULONG uValueType,
3262 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
3263{
3264 Log4(("vgdrvNtRegistryEnumCallback: pwszValueName=%ls uValueType=%#x Value=%.*Rhxs\n", pwszValueName, uValueType, cbValue, pvValue));
3265
3266 /*
3267 * Filter out general service config values.
3268 */
3269 if ( RTUtf16ICmpAscii(pwszValueName, "Type") == 0
3270 || RTUtf16ICmpAscii(pwszValueName, "Start") == 0
3271 || RTUtf16ICmpAscii(pwszValueName, "ErrorControl") == 0
3272 || RTUtf16ICmpAscii(pwszValueName, "Tag") == 0
3273 || RTUtf16ICmpAscii(pwszValueName, "ImagePath") == 0
3274 || RTUtf16ICmpAscii(pwszValueName, "DisplayName") == 0
3275 || RTUtf16ICmpAscii(pwszValueName, "Group") == 0
3276 || RTUtf16ICmpAscii(pwszValueName, "DependOnGroup") == 0
3277 || RTUtf16ICmpAscii(pwszValueName, "DependOnService") == 0
3278 )
3279 {
3280 return STATUS_SUCCESS;
3281 }
3282
3283 /*
3284 * Convert the value name.
3285 */
3286 size_t cch = RTUtf16CalcUtf8Len(pwszValueName);
3287 if (cch < 64 && cch > 0)
3288 {
3289 char szValueName[72];
3290 char *pszTmp = szValueName;
3291 int rc = RTUtf16ToUtf8Ex(pwszValueName, RTSTR_MAX, &pszTmp, sizeof(szValueName), NULL);
3292 if (RT_SUCCESS(rc))
3293 {
3294 /*
3295 * Convert the value.
3296 */
3297 char szValue[72];
3298 char *pszFree = NULL;
3299 char *pszValue = NULL;
3300 szValue[0] = '\0';
3301 switch (uValueType)
3302 {
3303 case REG_SZ:
3304 case REG_EXPAND_SZ:
3305 rc = RTUtf16CalcUtf8LenEx((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &cch);
3306 if (RT_SUCCESS(rc) && cch < _1K)
3307 {
3308 if (cch < sizeof(szValue))
3309 {
3310 pszValue = szValue;
3311 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &pszValue, sizeof(szValue), NULL);
3312 }
3313 else
3314 {
3315 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &pszValue, sizeof(szValue), NULL);
3316 if (RT_SUCCESS(rc))
3317 pszFree = pszValue;
3318 }
3319 if (RT_FAILURE(rc))
3320 {
3321 LogRel(("VBoxGuest: Failed to convert registry value '%ls' string data to UTF-8: %Rrc\n",
3322 pwszValueName, rc));
3323 pszValue = NULL;
3324 }
3325 }
3326 else if (RT_SUCCESS(rc))
3327 LogRel(("VBoxGuest: Registry value '%ls' has a too long value: %#x (uvalueType=%#x)\n",
3328 pwszValueName, cbValue, uValueType));
3329 else
3330 LogRel(("VBoxGuest: Registry value '%ls' has an invalid string value (cbValue=%#x, uvalueType=%#x)\n",
3331 pwszValueName, cbValue, uValueType));
3332 break;
3333
3334 case REG_DWORD:
3335 if (cbValue == sizeof(uint32_t))
3336 {
3337 RTStrFormatU32(szValue, sizeof(szValue), *(uint32_t const *)pvValue, 10, 0, 0, 0);
3338 pszValue = szValue;
3339 }
3340 else
3341 LogRel(("VBoxGuest: Registry value '%ls' has wrong length for REG_DWORD: %#x\n", pwszValueName, cbValue));
3342 break;
3343
3344 case REG_QWORD:
3345 if (cbValue == sizeof(uint64_t))
3346 {
3347 RTStrFormatU32(szValue, sizeof(szValue), *(uint32_t const *)pvValue, 10, 0, 0, 0);
3348 pszValue = szValue;
3349 }
3350 else
3351 LogRel(("VBoxGuest: Registry value '%ls' has wrong length for REG_DWORD: %#x\n", pwszValueName, cbValue));
3352 break;
3353
3354 default:
3355 LogRel(("VBoxGuest: Ignoring registry value '%ls': Unsupported type %#x\n", pwszValueName, uValueType));
3356 break;
3357 }
3358 if (pszValue)
3359 {
3360 /*
3361 * Process it.
3362 */
3363 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
3364 VGDrvCommonProcessOption(pDevExt, szValueName, pszValue);
3365 if (pszFree)
3366 RTStrFree(pszFree);
3367 }
3368 }
3369 }
3370 else if (cch > 0)
3371 LogRel(("VBoxGuest: Ignoring registery value '%ls': name too long\n", pwszValueName));
3372 else
3373 LogRel(("VBoxGuest: Ignoring registery value with bad name\n", pwszValueName));
3374 NOREF(pvEntryCtx);
3375 return STATUS_SUCCESS;
3376}
3377
3378
3379/**
3380 * Reads configuration from the registry and guest properties.
3381 *
3382 * We ignore failures and instead preserve existing configuration values.
3383 *
3384 * Thie routine will block.
3385 *
3386 * @param pDevExt The device extension.
3387 */
3388static void vgdrvNtReadConfiguration(PVBOXGUESTDEVEXTWIN pDevExt)
3389{
3390 /*
3391 * First the registry.
3392 *
3393 * Note! RTL_QUERY_REGISTRY_NOEXPAND is sensible (no environment) and also necessary to
3394 * avoid crash on NT 3.1 because RtlExpandEnvironmentStrings_U thinks its in ring-3
3395 * and tries to get the default heap from the PEB via the TEB. No TEB in ring-0.
3396 */
3397 RTL_QUERY_REGISTRY_TABLE aQuery[2];
3398 RT_ZERO(aQuery);
3399 aQuery[0].QueryRoutine = vgdrvNtRegistryEnumCallback;
3400 aQuery[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
3401 aQuery[0].Name = NULL;
3402 aQuery[0].EntryContext = NULL;
3403 aQuery[0].DefaultType = REG_NONE;
3404 NTSTATUS rcNt = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, L"VBoxGuest", &aQuery[0], pDevExt, NULL /*pwszzEnv*/);
3405 if (!NT_SUCCESS(rcNt))
3406 LogRel(("VBoxGuest: RtlQueryRegistryValues failed: %#x\n", rcNt));
3407
3408 /*
3409 * Read configuration from the host.
3410 */
3411 VGDrvCommonProcessOptionsFromHost(&pDevExt->Core);
3412}
3413
3414#ifdef VBOX_STRICT
3415
3416/**
3417 * A quick implementation of AtomicTestAndClear for uint32_t and multiple bits.
3418 */
3419static uint32_t vgdrvNtAtomicBitsTestAndClear(void *pu32Bits, uint32_t u32Mask)
3420{
3421 AssertPtrReturn(pu32Bits, 0);
3422 LogFlowFunc(("*pu32Bits=%#x, u32Mask=%#x\n", *(uint32_t *)pu32Bits, u32Mask));
3423 uint32_t u32Result = 0;
3424 uint32_t u32WorkingMask = u32Mask;
3425 int iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
3426
3427 while (iBitOffset > 0)
3428 {
3429 bool fSet = ASMAtomicBitTestAndClear(pu32Bits, iBitOffset - 1);
3430 if (fSet)
3431 u32Result |= 1 << (iBitOffset - 1);
3432 u32WorkingMask &= ~(1 << (iBitOffset - 1));
3433 iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
3434 }
3435 LogFlowFunc(("Returning %#x\n", u32Result));
3436 return u32Result;
3437}
3438
3439
3440static void vgdrvNtTestAtomicTestAndClearBitsU32(uint32_t u32Mask, uint32_t u32Bits, uint32_t u32Exp)
3441{
3442 ULONG u32Bits2 = u32Bits;
3443 uint32_t u32Result = vgdrvNtAtomicBitsTestAndClear(&u32Bits2, u32Mask);
3444 if ( u32Result != u32Exp
3445 || (u32Bits2 & u32Mask)
3446 || (u32Bits2 & u32Result)
3447 || ((u32Bits2 | u32Result) != u32Bits)
3448 )
3449 AssertLogRelMsgFailed(("TEST FAILED: u32Mask=%#x, u32Bits (before)=%#x, u32Bits (after)=%#x, u32Result=%#x, u32Exp=%#x\n",
3450 u32Mask, u32Bits, u32Bits2, u32Result));
3451}
3452
3453
3454static void vgdrvNtDoTests(void)
3455{
3456 vgdrvNtTestAtomicTestAndClearBitsU32(0x00, 0x23, 0);
3457 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0, 0);
3458 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x22, 0);
3459 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x23, 0x1);
3460 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x32, 0x10);
3461 vgdrvNtTestAtomicTestAndClearBitsU32(0x22, 0x23, 0x22);
3462}
3463
3464#endif /* VBOX_STRICT */
3465
3466#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
3467
3468/*
3469 * DPC latency checker.
3470 */
3471
3472/**
3473 * One DPC latency sample.
3474 */
3475typedef struct DPCSAMPLE
3476{
3477 LARGE_INTEGER PerfDelta;
3478 LARGE_INTEGER PerfCounter;
3479 LARGE_INTEGER PerfFrequency;
3480 uint64_t u64TSC;
3481} DPCSAMPLE;
3482AssertCompileSize(DPCSAMPLE, 4*8);
3483
3484/**
3485 * The DPC latency measurement workset.
3486 */
3487typedef struct DPCDATA
3488{
3489 KDPC Dpc;
3490 KTIMER Timer;
3491 KSPIN_LOCK SpinLock;
3492
3493 ULONG ulTimerRes;
3494
3495 bool volatile fFinished;
3496
3497 /** The timer interval (relative). */
3498 LARGE_INTEGER DueTime;
3499
3500 LARGE_INTEGER PerfCounterPrev;
3501
3502 /** Align the sample array on a 64 byte boundrary just for the off chance
3503 * that we'll get cache line aligned memory backing this structure. */
3504 uint32_t auPadding[ARCH_BITS == 32 ? 5 : 7];
3505
3506 int cSamples;
3507 DPCSAMPLE aSamples[8192];
3508} DPCDATA;
3509
3510AssertCompileMemberAlignment(DPCDATA, aSamples, 64);
3511
3512/**
3513 * DPC callback routine for the DPC latency measurement code.
3514 *
3515 * @param pDpc The DPC, not used.
3516 * @param pvDeferredContext Pointer to the DPCDATA.
3517 * @param SystemArgument1 System use, ignored.
3518 * @param SystemArgument2 System use, ignored.
3519 */
3520static VOID vgdrvNtDpcLatencyCallback(PKDPC pDpc, PVOID pvDeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
3521{
3522 DPCDATA *pData = (DPCDATA *)pvDeferredContext;
3523 RT_NOREF(pDpc, SystemArgument1, SystemArgument2);
3524
3525 KeAcquireSpinLockAtDpcLevel(&pData->SpinLock);
3526
3527 if (pData->cSamples >= RT_ELEMENTS(pData->aSamples))
3528 pData->fFinished = true;
3529 else
3530 {
3531 DPCSAMPLE *pSample = &pData->aSamples[pData->cSamples++];
3532
3533 pSample->u64TSC = ASMReadTSC();
3534 pSample->PerfCounter = KeQueryPerformanceCounter(&pSample->PerfFrequency);
3535 pSample->PerfDelta.QuadPart = pSample->PerfCounter.QuadPart - pData->PerfCounterPrev.QuadPart;
3536
3537 pData->PerfCounterPrev.QuadPart = pSample->PerfCounter.QuadPart;
3538
3539 KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
3540 }
3541
3542 KeReleaseSpinLockFromDpcLevel(&pData->SpinLock);
3543}
3544
3545
3546/**
3547 * Handles the DPC latency checker request.
3548 *
3549 * @returns VBox status code.
3550 */
3551int VGDrvNtIOCtl_DpcLatencyChecker(void)
3552{
3553 /*
3554 * Allocate a block of non paged memory for samples and related data.
3555 */
3556 DPCDATA *pData = (DPCDATA *)RTMemAlloc(sizeof(DPCDATA));
3557 if (!pData)
3558 {
3559 RTLogBackdoorPrintf("VBoxGuest: DPC: DPCDATA allocation failed.\n");
3560 return VERR_NO_MEMORY;
3561 }
3562
3563 /*
3564 * Initialize the data.
3565 */
3566 KeInitializeDpc(&pData->Dpc, vgdrvNtDpcLatencyCallback, pData);
3567 KeInitializeTimer(&pData->Timer);
3568 KeInitializeSpinLock(&pData->SpinLock);
3569
3570 pData->fFinished = false;
3571 pData->cSamples = 0;
3572 pData->PerfCounterPrev.QuadPart = 0;
3573
3574 pData->ulTimerRes = ExSetTimerResolution(1000 * 10, 1);
3575 pData->DueTime.QuadPart = -(int64_t)pData->ulTimerRes / 10;
3576
3577 /*
3578 * Start the DPC measurements and wait for a full set.
3579 */
3580 KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
3581
3582 while (!pData->fFinished)
3583 {
3584 LARGE_INTEGER Interval;
3585 Interval.QuadPart = -100 * 1000 * 10;
3586 KeDelayExecutionThread(KernelMode, TRUE, &Interval);
3587 }
3588
3589 ExSetTimerResolution(0, 0);
3590
3591 /*
3592 * Log everything to the host.
3593 */
3594 RTLogBackdoorPrintf("DPC: ulTimerRes = %d\n", pData->ulTimerRes);
3595 for (int i = 0; i < pData->cSamples; i++)
3596 {
3597 DPCSAMPLE *pSample = &pData->aSamples[i];
3598
3599 RTLogBackdoorPrintf("[%d] pd %lld pc %lld pf %lld t %lld\n",
3600 i,
3601 pSample->PerfDelta.QuadPart,
3602 pSample->PerfCounter.QuadPart,
3603 pSample->PerfFrequency.QuadPart,
3604 pSample->u64TSC);
3605 }
3606
3607 RTMemFree(pData);
3608 return VINF_SUCCESS;
3609}
3610
3611#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
3612
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