VirtualBox

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

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

Additions/common/VBoxGuest: Implement support for the MMIO request interface on Windows for win.arm64 support, bugref:10734

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 136.5 KB
Line 
1/* $Id: VBoxGuest-win.cpp 106461 2024-10-17 14:57:44Z 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 /** Physical address and length of the optional VMMDev MMIO request interface. */
155 PHYSICAL_ADDRESS GCPhysMmioReq;
156 /** Length of the optional VMMDev MMIO request interface. */
157 ULONG cbMmioReq;
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 {
785 /* Treat as MMIO request interface. */
786 /* Save physical MMIO base + length for VMMDev. */
787 pDevExt->GCPhysMmioReq = pPartialData->u.Memory.Start;
788 pDevExt->cbMmioReq = (ULONG)pPartialData->u.Memory.Length;
789
790 if (!fTranslated)
791 {
792 /* Technically we need to make the HAL translate the address. since we
793 didn't used to do this and it probably just returns the input address,
794 we allow ourselves to ignore failures. */
795 ULONG uAddressSpace = 0;
796 PHYSICAL_ADDRESS PhysAddr = pPartialData->u.Memory.Start;
797 if (HalTranslateBusAddress(pResList->List->InterfaceType, pResList->List->BusNumber, PhysAddr,
798 &uAddressSpace, &PhysAddr))
799 {
800 Log(("HalTranslateBusAddress(%#RX64) -> %RX64, type %#x\n",
801 pPartialData->u.Memory.Start.QuadPart, PhysAddr.QuadPart, uAddressSpace));
802 if (pPartialData->u.Memory.Start.QuadPart != PhysAddr.QuadPart)
803 pDevExt->GCPhysMmioReq = PhysAddr;
804 }
805 else
806 Log(("HalTranslateBusAddress(%#RX64) -> failed!\n", pPartialData->u.Memory.Start.QuadPart));
807 }
808
809 LogFunc(("Found memory range for VMMDev MMIO request interface! Base = %#RX64, Length = %08x\n",
810 pPartialData->u.Memory.Start.QuadPart, pPartialData->u.Memory.Length));
811 }
812 else
813 LogFunc(("Ignoring memory: Flags=%08x Base=%#RX64\n",
814 pPartialData->Flags, pPartialData->u.Memory.Start.QuadPart));
815 break;
816
817 default:
818 LogFunc(("Unhandled resource found, type=%d\n", pPartialData->Type));
819 break;
820 }
821 }
822 return rc;
823}
824
825
826#ifdef TARGET_NT4
827
828/**
829 * Scans the PCI resources on NT 3.1.
830 *
831 * @returns STATUS_SUCCESS or STATUS_DEVICE_CONFIGURATION_ERROR.
832 * @param pDevExt The device extension.
833 * @param uBus The bus number.
834 * @param uSlot The PCI slot to scan.
835 */
836static NTSTATUS vgdrvNt31ScanSlotResources(PVBOXGUESTDEVEXTWIN pDevExt, ULONG uBus, ULONG uSlot)
837{
838 /*
839 * Disable memory mappings so we can determin the BAR lengths
840 * without upsetting other mappings.
841 */
842 uint16_t fCmd = 0;
843 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmd, VBOX_PCI_COMMAND, sizeof(fCmd));
844 if (fCmd & VBOX_PCI_COMMAND_MEMORY)
845 {
846 uint16_t fCmdTmp = fCmd & ~VBOX_PCI_COMMAND_MEMORY;
847 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmdTmp, VBOX_PCI_COMMAND, sizeof(fCmdTmp));
848 }
849
850 /*
851 * Scan the address resources first.
852 */
853 uint32_t aBars[6] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX };
854 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &aBars, VBOX_PCI_BASE_ADDRESS_0, sizeof(aBars));
855
856 bool fGotMmio = false;
857 bool fGotIoPorts = false;
858 for (uint32_t i = 0; i < RT_ELEMENTS(aBars); i++)
859 {
860 uint32_t uBar = aBars[i];
861 if (uBar == UINT32_MAX)
862 continue;
863 if ((uBar & 1) == PCI_ADDRESS_SPACE_IO)
864 {
865 uint32_t uAddr = uBar & UINT32_C(0xfffffffc);
866 if (!uAddr)
867 continue;
868 if (!fGotIoPorts)
869 {
870 pDevExt->Core.IOPortBase = (uint16_t)uAddr & UINT16_C(0xfffc);
871 fGotIoPorts = true;
872 LogFunc(("I/O range for VMMDev found in BAR%u! %#x\n", i, pDevExt->Core.IOPortBase));
873 }
874 else
875 LogRelFunc(("More than one I/O port range?!? BAR%u=%#x\n", i, uBar));
876 }
877 else
878 {
879 uint32_t uAddr = uBar & UINT32_C(0xfffffff0);
880 if (!uAddr)
881 continue;
882
883 if (!fGotMmio)
884 {
885 /* Figure the length by trying to set all address bits and seeing
886 how many we're allowed to set. */
887 uint32_t iBit = 4;
888 while (!(uAddr & RT_BIT_32(iBit)))
889 iBit++;
890
891 uint32_t const offPciBar = VBOX_PCI_BASE_ADDRESS_0 + i * 4;
892 uint32_t uTmpBar = uBar | ((RT_BIT_32(iBit) - 1) & UINT32_C(0xfffffff0));
893 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &uTmpBar, offPciBar, sizeof(uTmpBar));
894 uTmpBar = uBar;
895 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &uTmpBar, offPciBar, sizeof(uTmpBar));
896 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &uBar, offPciBar, sizeof(uBar));
897
898 while (iBit > 4 && (uTmpBar & RT_BIT_32(iBit - 1)))
899 iBit--;
900
901 /* got it */
902 pDevExt->cbVmmDevMemory = RT_BIT_32(iBit);
903 pDevExt->uVmmDevMemoryPhysAddr.QuadPart = uAddr;
904 fGotMmio = true;
905 LogFunc(("Found memory range for VMMDev in BAR%u! %#RX64 LB %#x (raw %#x)\n",
906 i, pDevExt->uVmmDevMemoryPhysAddr.QuadPart, pDevExt->cbVmmDevMemory, uBar));
907 }
908 else
909 LogFunc(("Ignoring memory: BAR%u=%#x\n", i, uBar));
910 }
911 }
912
913 /*
914 * Get the IRQ
915 */
916 struct
917 {
918 uint8_t bInterruptLine;
919 uint8_t bInterruptPin;
920 } Buf = { 0, 0 };
921 g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, uSlot, &Buf, VBOX_PCI_INTERRUPT_LINE, sizeof(Buf));
922 if (Buf.bInterruptPin != 0)
923 {
924 pDevExt->uInterruptVector = Buf.bInterruptLine;
925 pDevExt->uInterruptLevel = Buf.bInterruptLine;
926 pDevExt->enmInterruptMode = LevelSensitive;
927 pDevExt->fInterruptAffinity = RT_BIT_32(RTMpGetCount()) - 1;
928 LogFunc(("Interrupt for VMMDev found! Vector=%#x Level=%#x Affinity=%zx Mode=%d\n",
929 pDevExt->uInterruptVector, pDevExt->uInterruptLevel, pDevExt->fInterruptAffinity, pDevExt->enmInterruptMode));
930 }
931
932 /*
933 * Got what we need?
934 */
935 if (fGotIoPorts && (!fGotMmio || Buf.bInterruptPin != 0))
936 {
937 /*
938 * Enable both MMIO, I/O space and busmastering so we can use the device.
939 */
940 uint16_t fCmdNew = fCmd | VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY | VBOX_PCI_COMMAND_MASTER;
941 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmdNew, VBOX_PCI_COMMAND, sizeof(fCmdNew));
942
943 return STATUS_SUCCESS;
944 }
945
946 /* No. Complain, restore device command value and return failure. */
947 if (!fGotIoPorts)
948 LogRel(("VBoxGuest: Did not find I/O port range: %#x %#x %#x %#x %#x %#x\n",
949 aBars[0], aBars[1], aBars[2], aBars[3], aBars[4], aBars[5]));
950 if (!fGotMmio || Buf.bInterruptPin != 0)
951 LogRel(("VBoxGuest: Got MMIO but no interrupts!\n"));
952
953 g_pfnHalSetBusDataByOffset(PCIConfiguration, uBus, uSlot, &fCmd, VBOX_PCI_COMMAND, sizeof(fCmd));
954 return STATUS_DEVICE_CONFIGURATION_ERROR;
955}
956
957#endif /* TARGET_NT4 */
958
959/**
960 * Unmaps the VMMDev I/O range from kernel space.
961 *
962 * @param pDevExt The device extension.
963 */
964static void vgdrvNtUnmapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt)
965{
966 LogFlowFunc(("pVMMDevMemory = %#x\n", pDevExt->Core.pVMMDevMemory));
967 if (pDevExt->Core.pVMMDevMemory)
968 {
969 MmUnmapIoSpace((void*)pDevExt->Core.pVMMDevMemory, pDevExt->cbVmmDevMemory);
970 pDevExt->Core.pVMMDevMemory = NULL;
971 }
972
973 pDevExt->uVmmDevMemoryPhysAddr.QuadPart = 0;
974 pDevExt->cbVmmDevMemory = 0;
975}
976
977
978/**
979 * Unmaps the MMIO request interface range from kernel space.
980 *
981 * @param pDevExt The device extension.
982 */
983static void vgdrvNtUnmapVMMDevMmioReq(PVBOXGUESTDEVEXTWIN pDevExt)
984{
985 LogFlowFunc(("pMmioReq = %#p\n", pDevExt->Core.pMmioReq));
986 if (pDevExt->Core.pMmioReq)
987 {
988 MmUnmapIoSpace((void*)pDevExt->Core.pMmioReq, pDevExt->cbMmioReq);
989 pDevExt->Core.pMmioReq = NULL;
990 pDevExt->Core.pMmioReqFast = NULL;
991 }
992
993 pDevExt->GCPhysMmioReq.QuadPart = 0;
994 pDevExt->cbMmioReq = 0;
995}
996
997
998/**
999 * Maps the I/O space from VMMDev to virtual kernel address space.
1000 *
1001 * @return NTSTATUS
1002 *
1003 * @param pDevExt The device extension.
1004 * @param PhysAddr Physical address to map.
1005 * @param cbToMap Number of bytes to map.
1006 * @param ppvMMIOBase Pointer of mapped I/O base.
1007 * @param pcbMMIO Length of mapped I/O base.
1008 */
1009static NTSTATUS vgdrvNtMapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS PhysAddr, ULONG cbToMap,
1010 void **ppvMMIOBase, uint32_t *pcbMMIO)
1011{
1012 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1013 AssertPtrReturn(ppvMMIOBase, VERR_INVALID_POINTER);
1014 /* pcbMMIO is optional. */
1015
1016 NTSTATUS rc = STATUS_SUCCESS;
1017 if (PhysAddr.LowPart > 0) /* We're mapping below 4GB. */
1018 {
1019 VMMDevMemory *pVMMDevMemory = (VMMDevMemory *)MmMapIoSpace(PhysAddr, cbToMap, MmNonCached);
1020 LogFlowFunc(("pVMMDevMemory = %#x\n", pVMMDevMemory));
1021 if (pVMMDevMemory)
1022 {
1023 LogFunc(("VMMDevMemory: Version = %#x, Size = %d\n", pVMMDevMemory->u32Version, pVMMDevMemory->u32Size));
1024
1025 /* Check version of the structure; do we have the right memory version? */
1026 if (pVMMDevMemory->u32Version == VMMDEV_MEMORY_VERSION)
1027 {
1028 /* Save results. */
1029 *ppvMMIOBase = pVMMDevMemory;
1030 if (pcbMMIO) /* Optional. */
1031 *pcbMMIO = pVMMDevMemory->u32Size;
1032
1033 LogFlowFunc(("VMMDevMemory found and mapped! pvMMIOBase = 0x%p\n", *ppvMMIOBase));
1034 }
1035 else
1036 {
1037 /* Not our version, refuse operation and unmap the memory. */
1038 LogFunc(("Wrong version (%u), refusing operation!\n", pVMMDevMemory->u32Version));
1039
1040 vgdrvNtUnmapVMMDevMemory(pDevExt);
1041 rc = STATUS_UNSUCCESSFUL;
1042 }
1043 }
1044 else
1045 rc = STATUS_UNSUCCESSFUL;
1046 }
1047 return rc;
1048}
1049
1050
1051/**
1052 * Maps the I/O space from VMMDev to virtual kernel address space.
1053 *
1054 * @return NTSTATUS
1055 *
1056 * @param pDevExt The device extension.
1057 * @param GCPhysMmioReq Physical address to map.
1058 * @param cbToMap Number of bytes to map.
1059 * @param ppvMmioReq Pointer of mapped I/O base.
1060 */
1061static NTSTATUS vgdrvNtMapVMMDevMmioReq(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS GCPhysMmioReq, ULONG cbToMap,
1062 void **ppvMmioReq)
1063{
1064 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1065 AssertPtrReturn(ppvMmioReq, VERR_INVALID_POINTER);
1066
1067 NTSTATUS rc = STATUS_SUCCESS;
1068 if (GCPhysMmioReq.QuadPart != 0)
1069 {
1070 void *pvMmioReq = MmMapIoSpace(GCPhysMmioReq, cbToMap, MmNonCached);
1071 LogFlowFunc(("pvMmioReq = %p\n", pvMmioReq));
1072 if (pvMmioReq)
1073 {
1074 /* Save results. */
1075 *ppvMmioReq = pvMmioReq;
1076 LogFlowFunc(("MMIO request interface found and mapped! pvMmioReq = 0x%p\n", pvMmioReq));
1077 }
1078 else
1079 rc = STATUS_UNSUCCESSFUL;
1080 }
1081 return rc;
1082}
1083
1084
1085/**
1086 * Sets up the device and its resources.
1087 *
1088 * @param pDevExt Our device extension data.
1089 * @param pDevObj The device object.
1090 * @param pIrp The request packet if NT5+, NULL for NT4 and earlier.
1091 * @param pDrvObj The driver object for NT4, NULL for NT5+.
1092 * @param pRegPath The registry path for NT4, NULL for NT5+.
1093 */
1094static NTSTATUS vgdrvNtSetupDevice(PVBOXGUESTDEVEXTWIN pDevExt, PDEVICE_OBJECT pDevObj,
1095 PIRP pIrp, PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1096{
1097 LogFlowFunc(("ENTER: pDevExt=%p pDevObj=%p pIrq=%p pDrvObj=%p pRegPath=%p\n", pDevExt, pDevObj, pIrp, pDrvObj, pRegPath));
1098
1099 NTSTATUS rcNt;
1100 if (!pIrp)
1101 {
1102#ifdef TARGET_NT4
1103 /*
1104 * NT4, NT3.x: Let's have a look at what our PCI adapter offers.
1105 */
1106 LogFlowFunc(("Starting to scan PCI resources of VBoxGuest ...\n"));
1107
1108 /* Assign the PCI resources. */
1109 UNICODE_STRING ClassName;
1110 RtlInitUnicodeString(&ClassName, L"VBoxGuestAdapter");
1111 PCM_RESOURCE_LIST pResourceList = NULL;
1112 if (g_pfnHalAssignSlotResources)
1113 {
1114 rcNt = g_pfnHalAssignSlotResources(pRegPath, &ClassName, pDrvObj, pDevObj, PCIBus, pDevExt->uBus, pDevExt->uSlot,
1115 &pResourceList);
1116# ifdef LOG_ENABLED
1117 if (pResourceList)
1118 vgdrvNtShowDeviceResources(pResourceList);
1119# endif
1120 if (NT_SUCCESS(rcNt))
1121 {
1122 rcNt = vgdrvNtScanPCIResourceList(pDevExt, pResourceList, false /*fTranslated*/);
1123 ExFreePool(pResourceList);
1124 }
1125 }
1126 else
1127 rcNt = vgdrvNt31ScanSlotResources(pDevExt, pDevExt->uBus, pDevExt->uSlot);
1128
1129# else /* !TARGET_NT4 */
1130 AssertFailed();
1131 RT_NOREF(pDevObj, pDrvObj, pRegPath);
1132 rcNt = STATUS_INTERNAL_ERROR;
1133# endif /* !TARGET_NT4 */
1134 }
1135 else
1136 {
1137 /*
1138 * NT5+: Scan the PCI resource list from the IRP.
1139 */
1140 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1141# ifdef LOG_ENABLED
1142 vgdrvNtShowDeviceResources(pStack->Parameters.StartDevice.AllocatedResourcesTranslated);
1143# endif
1144 rcNt = vgdrvNtScanPCIResourceList(pDevExt, pStack->Parameters.StartDevice.AllocatedResourcesTranslated,
1145 true /*fTranslated*/);
1146 }
1147 if (NT_SUCCESS(rcNt))
1148 {
1149 /*
1150 * Map physical address of VMMDev memory into MMIO region
1151 * and init the common device extension bits.
1152 */
1153 void *pvMMIOBase = NULL;
1154 uint32_t cbMMIO = 0;
1155 rcNt = vgdrvNtMapVMMDevMemory(pDevExt,
1156 pDevExt->uVmmDevMemoryPhysAddr,
1157 pDevExt->cbVmmDevMemory,
1158 &pvMMIOBase,
1159 &cbMMIO);
1160 if (NT_SUCCESS(rcNt))
1161 {
1162 pDevExt->Core.pVMMDevMemory = (VMMDevMemory *)pvMMIOBase;
1163
1164 void *pvMmioReq = NULL;
1165 rcNt = vgdrvNtMapVMMDevMmioReq(pDevExt, pDevExt->GCPhysMmioReq, pDevExt->cbMmioReq, &pvMmioReq);
1166 if (NT_SUCCESS(rcNt))
1167 {
1168 LogFunc(("pvMMIOBase=0x%p, pDevExt=0x%p, pDevExt->Core.pVMMDevMemory=0x%p\n",
1169 pvMMIOBase, pDevExt, pDevExt ? pDevExt->Core.pVMMDevMemory : NULL));
1170
1171 int vrc = VGDrvCommonInitDevExtResources(&pDevExt->Core,
1172 pDevExt->Core.IOPortBase,
1173 pvMmioReq,
1174 pvMMIOBase, cbMMIO,
1175 vgdrvNtVersionToOSType(g_enmVGDrvNtVer),
1176 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
1177 if (RT_SUCCESS(vrc))
1178 {
1179
1180 vrc = VbglR0GRAlloc((VMMDevRequestHeader **)&pDevExt->pPowerStateRequest,
1181 sizeof(VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
1182 if (RT_SUCCESS(vrc))
1183 {
1184 /*
1185 * Register DPC and ISR.
1186 */
1187 LogFlowFunc(("Initializing DPC/ISR (pDevObj=%p)...\n", pDevExt->pDeviceObject));
1188 IoInitializeDpcRequest(pDevExt->pDeviceObject, vgdrvNtDpcHandler);
1189
1190 ULONG uInterruptVector = pDevExt->uInterruptVector;
1191 KIRQL uHandlerIrql = (KIRQL)pDevExt->uInterruptLevel;
1192 #ifdef TARGET_NT4
1193 if (!pIrp)
1194 {
1195 /* NT4: Get an interrupt vector. Only proceed if the device provides an interrupt. */
1196 if ( uInterruptVector
1197 || pDevExt->uInterruptLevel)
1198 {
1199 LogFlowFunc(("Getting interrupt vector (HAL): Bus=%u, IRQL=%u, Vector=%u\n",
1200 pDevExt->uBus, pDevExt->uInterruptLevel, pDevExt->uInterruptVector));
1201 uInterruptVector = HalGetInterruptVector(g_enmVGDrvNtVer == VGDRVNTVER_WINNT310 ? Isa : PCIBus,
1202 pDevExt->uBus,
1203 pDevExt->uInterruptLevel,
1204 pDevExt->uInterruptVector,
1205 &uHandlerIrql,
1206 &pDevExt->fInterruptAffinity);
1207 LogFlowFunc(("HalGetInterruptVector returns vector=%u\n", uInterruptVector));
1208 }
1209 else
1210 LogFunc(("Device does not provide an interrupt!\n"));
1211 }
1212 #endif
1213 if (uInterruptVector)
1214 {
1215 LogFlowFunc(("Connecting interrupt (IntVector=%#u), uHandlerIrql=%u) ...\n",
1216 uInterruptVector, uHandlerIrql));
1217
1218 rcNt = IoConnectInterrupt(&pDevExt->pInterruptObject, /* Out: interrupt object. */
1219 vgdrvNtIsrHandler, /* Our ISR handler. */
1220 pDevExt, /* Device context. */
1221 NULL, /* Optional spinlock. */
1222 uInterruptVector, /* Interrupt vector. */
1223 uHandlerIrql, /* Irql. */
1224 uHandlerIrql, /* SynchronizeIrql. */
1225 pDevExt->enmInterruptMode, /* LevelSensitive or Latched. */
1226 TRUE, /* Shareable interrupt. */
1227 pDevExt->fInterruptAffinity, /* CPU affinity. */
1228 FALSE); /* Don't save FPU stack. */
1229 if (NT_ERROR(rcNt))
1230 LogFunc(("Could not connect interrupt: rcNt=%#x!\n", rcNt));
1231 }
1232 else
1233 LogFunc(("No interrupt vector found!\n"));
1234 if (NT_SUCCESS(rcNt))
1235 {
1236 /*
1237 * Once we've read configuration from register and host, we're finally read.
1238 */
1239 /** @todo clean up guest ring-3 logging, keeping it separate from the kernel to avoid sharing limits with it. */
1240 pDevExt->Core.fLoggingEnabled = true;
1241 vgdrvNtReadConfiguration(pDevExt);
1242
1243 /* Ready to rumble! */
1244 LogRelFunc(("Device is ready!\n"));
1245 pDevExt->enmDevState = VGDRVNTDEVSTATE_OPERATIONAL;
1246 pDevExt->enmPrevDevState = VGDRVNTDEVSTATE_OPERATIONAL;
1247 return STATUS_SUCCESS;
1248 }
1249
1250 pDevExt->pInterruptObject = NULL;
1251
1252 VbglR0GRFree(&pDevExt->pPowerStateRequest->header);
1253 pDevExt->pPowerStateRequest = NULL;
1254 }
1255 else
1256 {
1257 LogFunc(("Alloc for pPowerStateRequest failed, vrc=%Rrc\n", vrc));
1258 rcNt = STATUS_UNSUCCESSFUL;
1259 }
1260
1261 VGDrvCommonDeleteDevExtResources(&pDevExt->Core);
1262 }
1263 else
1264 {
1265 LogFunc(("Could not init device extension resources: vrc=%Rrc\n", vrc));
1266 rcNt = STATUS_DEVICE_CONFIGURATION_ERROR;
1267 }
1268 vgdrvNtUnmapVMMDevMmioReq(pDevExt);
1269 }
1270 else
1271 LogFunc(("Could not map MMIO request interface of VMMDec, rcNt=%#x\n", rcNt));
1272 vgdrvNtUnmapVMMDevMemory(pDevExt);
1273 }
1274 else
1275 LogFunc(("Could not map physical address of VMMDev, rcNt=%#x\n", rcNt));
1276 }
1277
1278 LogFunc(("Returned with rcNt=%#x\n", rcNt));
1279 return rcNt;
1280}
1281
1282
1283
1284
1285#ifdef TARGET_NT4
1286# define PCI_CFG_ADDR 0xcf8
1287# define PCI_CFG_DATA 0xcfc
1288
1289/**
1290 * NT 3.1 doesn't do PCI nor HalSetBusDataByOffset, this is our fallback.
1291 */
1292static ULONG NTAPI vgdrvNt31SetBusDataByOffset(BUS_DATA_TYPE enmBusDataType, ULONG idxBus, ULONG uSlot,
1293 void *pvData, ULONG offData, ULONG cbData)
1294{
1295 /*
1296 * Validate input a little bit.
1297 */
1298 RT_NOREF(enmBusDataType);
1299 Assert(idxBus <= 255);
1300 Assert(uSlot <= 255);
1301 Assert(offData <= 255);
1302 Assert(cbData > 0);
1303
1304 PCI_SLOT_NUMBER PciSlot;
1305 PciSlot.u.AsULONG = uSlot;
1306 uint32_t const idxAddrTop = UINT32_C(0x80000000)
1307 | (idxBus << 16)
1308 | (PciSlot.u.bits.DeviceNumber << 11)
1309 | (PciSlot.u.bits.FunctionNumber << 8);
1310
1311 /*
1312 * Write the given bytes.
1313 */
1314 uint8_t const *pbData = (uint8_t const *)pvData;
1315 uint32_t off = offData;
1316 uint32_t cbRet = 0;
1317
1318 /* Unaligned start. */
1319 if (off & 3)
1320 {
1321 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | (off & ~3));
1322 switch (off & 3)
1323 {
1324 case 1:
1325 ASMOutU8(PCI_CFG_DATA + 1, pbData[cbRet++]);
1326 if (cbRet >= cbData)
1327 break;
1328 RT_FALL_THRU();
1329 case 2:
1330 ASMOutU8(PCI_CFG_DATA + 2, pbData[cbRet++]);
1331 if (cbRet >= cbData)
1332 break;
1333 RT_FALL_THRU();
1334 case 3:
1335 ASMOutU8(PCI_CFG_DATA + 3, pbData[cbRet++]);
1336 break;
1337 }
1338 off = (off | 3) + 1;
1339 }
1340
1341 /* Bulk. */
1342 while (off < 256 && cbRet < cbData)
1343 {
1344 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | off);
1345 switch (cbData - cbRet)
1346 {
1347 case 1:
1348 ASMOutU8(PCI_CFG_DATA, pbData[cbRet]);
1349 cbRet += 1;
1350 break;
1351 case 2:
1352 ASMOutU16(PCI_CFG_DATA, RT_MAKE_U16(pbData[cbRet], pbData[cbRet + 1]));
1353 cbRet += 2;
1354 break;
1355 case 3:
1356 ASMOutU16(PCI_CFG_DATA, RT_MAKE_U16(pbData[cbRet], pbData[cbRet + 1]));
1357 ASMOutU8(PCI_CFG_DATA + 2, pbData[cbRet + 2]);
1358 cbRet += 3;
1359 break;
1360 default:
1361 ASMOutU32(PCI_CFG_DATA, RT_MAKE_U32_FROM_U8(pbData[cbRet], pbData[cbRet + 1],
1362 pbData[cbRet + 2], pbData[cbRet + 3]));
1363 cbRet += 4;
1364 break;
1365 }
1366 off += 4;
1367 }
1368
1369 return cbRet;
1370}
1371
1372
1373/**
1374 * NT 3.1 doesn't do PCI nor HalGetBusDataByOffset, this is our fallback.
1375 */
1376static ULONG NTAPI vgdrvNt31GetBusDataByOffset(BUS_DATA_TYPE enmBusDataType, ULONG idxBus, ULONG uSlot,
1377 void *pvData, ULONG offData, ULONG cbData)
1378{
1379 /*
1380 * Validate input a little bit.
1381 */
1382 RT_NOREF(enmBusDataType);
1383 Assert(idxBus <= 255);
1384 Assert(uSlot <= 255);
1385 Assert(offData <= 255);
1386 Assert(cbData > 0);
1387
1388 PCI_SLOT_NUMBER PciSlot;
1389 PciSlot.u.AsULONG = uSlot;
1390 uint32_t const idxAddrTop = UINT32_C(0x80000000)
1391 | (idxBus << 16)
1392 | (PciSlot.u.bits.DeviceNumber << 11)
1393 | (PciSlot.u.bits.FunctionNumber << 8);
1394
1395 /*
1396 * Read the header type.
1397 */
1398 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | (VBOX_PCI_HEADER_TYPE & ~3));
1399 uint8_t bHdrType = ASMInU8(PCI_CFG_DATA + (VBOX_PCI_HEADER_TYPE & 3));
1400 if (bHdrType == 0xff)
1401 return idxBus < 8 ? 2 : 0; /* No device here */
1402 if ( offData == VBOX_PCI_HEADER_TYPE
1403 && cbData == 1)
1404 {
1405 *(uint8_t *)pvData = bHdrType;
1406 /*Log("vgdrvNt31GetBusDataByOffset: PCI %#x/%#x -> %02x\n", idxAddrTop, offData, bHdrType);*/
1407 return 1;
1408 }
1409
1410 /*
1411 * Read the requested bytes.
1412 */
1413 uint8_t *pbData = (uint8_t *)pvData;
1414 uint32_t off = offData;
1415 uint32_t cbRet = 0;
1416
1417 /* Unaligned start. */
1418 if (off & 3)
1419 {
1420 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | (off & ~3));
1421 uint32_t uValue = ASMInU32(PCI_CFG_DATA);
1422 switch (off & 3)
1423 {
1424 case 1:
1425 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1426 if (cbRet >= cbData)
1427 break;
1428 RT_FALL_THRU();
1429 case 2:
1430 pbData[cbRet++] = (uint8_t)(uValue >> 16);
1431 if (cbRet >= cbData)
1432 break;
1433 RT_FALL_THRU();
1434 case 3:
1435 pbData[cbRet++] = (uint8_t)(uValue >> 24);
1436 break;
1437 }
1438 off = (off | 3) + 1;
1439 }
1440
1441 /* Bulk. */
1442 while (off < 256 && cbRet < cbData)
1443 {
1444 ASMOutU32(PCI_CFG_ADDR, idxAddrTop | off);
1445 uint32_t uValue = ASMInU32(PCI_CFG_DATA);
1446 switch (cbData - cbRet)
1447 {
1448 case 1:
1449 pbData[cbRet++] = (uint8_t)uValue;
1450 break;
1451 case 2:
1452 pbData[cbRet++] = (uint8_t)uValue;
1453 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1454 break;
1455 case 3:
1456 pbData[cbRet++] = (uint8_t)uValue;
1457 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1458 pbData[cbRet++] = (uint8_t)(uValue >> 16);
1459 break;
1460 default:
1461 pbData[cbRet++] = (uint8_t)uValue;
1462 pbData[cbRet++] = (uint8_t)(uValue >> 8);
1463 pbData[cbRet++] = (uint8_t)(uValue >> 16);
1464 pbData[cbRet++] = (uint8_t)(uValue >> 24);
1465 break;
1466 }
1467 off += 4;
1468 }
1469
1470 Log(("vgdrvNt31GetBusDataByOffset: PCI %#x/%#x -> %.*Rhxs\n", idxAddrTop, offData, cbRet, pvData));
1471 return cbRet;
1472}
1473
1474
1475/**
1476 * Helper function to handle the PCI device lookup.
1477 *
1478 * @returns NT status code.
1479 *
1480 * @param puBus Where to return the bus number on success.
1481 * @param pSlot Where to return the slot number on success.
1482 */
1483static NTSTATUS vgdrvNt4FindPciDevice(PULONG puBus, PPCI_SLOT_NUMBER pSlot)
1484{
1485 Log(("vgdrvNt4FindPciDevice\n"));
1486
1487 PCI_SLOT_NUMBER Slot;
1488 Slot.u.AsULONG = 0;
1489
1490 /* Scan each bus. */
1491 for (ULONG uBus = 0; uBus < PCI_MAX_BUSES; uBus++)
1492 {
1493 /* Scan each device. */
1494 for (ULONG idxDevice = 0; idxDevice < PCI_MAX_DEVICES; idxDevice++)
1495 {
1496 Slot.u.bits.DeviceNumber = idxDevice;
1497 Slot.u.bits.FunctionNumber = 0;
1498
1499 /* Check the device header. */
1500 uint8_t bHeaderType = 0xff;
1501 ULONG cbRet = g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, Slot.u.AsULONG,
1502 &bHeaderType, VBOX_PCI_HEADER_TYPE, sizeof(bHeaderType));
1503 if (cbRet == 0)
1504 break;
1505 if (cbRet == 2 || bHeaderType == 0xff)
1506 continue;
1507
1508 /* Scan functions. */
1509 uint32_t const cFunctionStep = bHeaderType & 0x80 ? 1 : 8;
1510 Log(("vgdrvNt4FindPciDevice: %#x:%#x cFunctionStep=%d bHeaderType=%#x\n", uBus, idxDevice, cFunctionStep, bHeaderType));
1511 for (ULONG idxFunction = 0; idxFunction < PCI_MAX_FUNCTION; idxFunction += cFunctionStep)
1512 {
1513 Slot.u.bits.FunctionNumber = idxFunction;
1514
1515 /* Read the vendor and device IDs of this device and compare with the VMMDev. */
1516 struct
1517 {
1518 uint16_t idVendor;
1519 uint16_t idDevice;
1520 } Buf = { PCI_INVALID_VENDORID, PCI_INVALID_VENDORID };
1521 cbRet = g_pfnHalGetBusDataByOffset(PCIConfiguration, uBus, Slot.u.AsULONG, &Buf, VBOX_PCI_VENDOR_ID, sizeof(Buf));
1522 if ( cbRet == sizeof(Buf)
1523 && Buf.idVendor == VMMDEV_VENDORID
1524 && Buf.idDevice == VMMDEV_DEVICEID)
1525 {
1526 /* Hooray, we've found it! */
1527 Log(("vgdrvNt4FindPciDevice: Device found! Bus=%#x Slot=%#u (dev %#x, fun %#x, rvd %#x)\n",
1528 uBus, Slot.u.AsULONG, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber, Slot.u.bits.Reserved));
1529
1530 *puBus = uBus;
1531 *pSlot = Slot;
1532 return STATUS_SUCCESS;
1533 }
1534 }
1535 }
1536 }
1537
1538 return STATUS_DEVICE_DOES_NOT_EXIST;
1539}
1540
1541
1542/**
1543 * Legacy helper function to create the device object.
1544 *
1545 * @returns NT status code.
1546 *
1547 * @param pDrvObj The driver object.
1548 * @param pRegPath The driver registry path.
1549 */
1550static NTSTATUS vgdrvNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1551{
1552 Log(("vgdrvNt4CreateDevice: pDrvObj=%p, pRegPath=%p\n", pDrvObj, pRegPath));
1553
1554 /*
1555 * Find our virtual PCI device
1556 */
1557 ULONG uBus;
1558 PCI_SLOT_NUMBER uSlot;
1559 NTSTATUS rc = vgdrvNt4FindPciDevice(&uBus, &uSlot);
1560 if (NT_ERROR(rc))
1561 {
1562 Log(("vgdrvNt4CreateDevice: Device not found!\n"));
1563 return rc;
1564 }
1565
1566 /*
1567 * Create device.
1568 */
1569 UNICODE_STRING DevName;
1570 RtlInitUnicodeString(&DevName, VBOXGUEST_DEVICE_NAME_NT);
1571 PDEVICE_OBJECT pDeviceObject = NULL;
1572 rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
1573 if (NT_SUCCESS(rc))
1574 {
1575 Log(("vgdrvNt4CreateDevice: Device created\n"));
1576
1577 UNICODE_STRING DosName;
1578 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
1579 rc = IoCreateSymbolicLink(&DosName, &DevName);
1580 if (NT_SUCCESS(rc))
1581 {
1582 Log(("vgdrvNt4CreateDevice: Symlink created\n"));
1583
1584 /*
1585 * Setup the device extension.
1586 */
1587 Log(("vgdrvNt4CreateDevice: Setting up device extension ...\n"));
1588 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
1589 int vrc = vgdrvNtInitDevExtFundament(pDevExt, pDeviceObject);
1590 if (RT_SUCCESS(vrc))
1591 {
1592 /* Store bus and slot number we've queried before. */
1593 pDevExt->uBus = uBus;
1594 pDevExt->uSlot = uSlot.u.AsULONG;
1595
1596 Log(("vgdrvNt4CreateDevice: Device extension created\n"));
1597
1598 /* Do the actual VBox init ... */
1599 rc = vgdrvNtSetupDevice(pDevExt, pDeviceObject, NULL /*pIrp*/, pDrvObj, pRegPath);
1600 if (NT_SUCCESS(rc))
1601 {
1602 Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x (success)\n", rc));
1603 return rc;
1604 }
1605
1606 /* bail out */
1607 vgdrvNtDeleteDevExtFundament(pDevExt);
1608 }
1609 IoDeleteSymbolicLink(&DosName);
1610 }
1611 else
1612 Log(("vgdrvNt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc));
1613 IoDeleteDevice(pDeviceObject);
1614 }
1615 else
1616 Log(("vgdrvNt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc));
1617 Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x\n", rc));
1618 return rc;
1619}
1620
1621#endif /* TARGET_NT4 */
1622
1623/**
1624 * Handle request from the Plug & Play subsystem.
1625 *
1626 * @returns NT status code
1627 * @param pDrvObj Driver object
1628 * @param pDevObj Device object
1629 *
1630 * @remarks Parts of this is duplicated in VBoxGuest-win-legacy.cpp.
1631 */
1632static NTSTATUS NTAPI vgdrvNtNt5PlusAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
1633{
1634 LogFlowFuncEnter();
1635
1636 /*
1637 * Create device.
1638 */
1639 UNICODE_STRING DevName;
1640 RtlInitUnicodeString(&DevName, VBOXGUEST_DEVICE_NAME_NT);
1641 PDEVICE_OBJECT pDeviceObject = NULL;
1642 NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
1643 if (NT_SUCCESS(rcNt))
1644 {
1645 /*
1646 * Create symbolic link (DOS devices).
1647 */
1648 UNICODE_STRING DosName;
1649 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
1650 rcNt = IoCreateSymbolicLink(&DosName, &DevName);
1651 if (NT_SUCCESS(rcNt))
1652 {
1653 /*
1654 * Setup the device extension.
1655 */
1656 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
1657 rcNt = vgdrvNtInitDevExtFundament(pDevExt, pDeviceObject);
1658 if (NT_SUCCESS(rcNt))
1659 {
1660 pDevExt->pNextLowerDriver = IoAttachDeviceToDeviceStack(pDeviceObject, pDevObj);
1661 if (pDevExt->pNextLowerDriver != NULL)
1662 {
1663 /* Ensure we are not called at elevated IRQL, even if our code isn't pagable any more. */
1664 pDeviceObject->Flags |= DO_POWER_PAGABLE;
1665
1666 /* Driver is ready now. */
1667 pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1668 LogFlowFunc(("Returning with rcNt=%#x (success)\n", rcNt));
1669 return rcNt;
1670 }
1671 LogFunc(("IoAttachDeviceToDeviceStack did not give a nextLowerDriver!\n"));
1672 rcNt = STATUS_DEVICE_NOT_CONNECTED;
1673 vgdrvNtDeleteDevExtFundament(pDevExt);
1674 }
1675
1676 IoDeleteSymbolicLink(&DosName);
1677 }
1678 else
1679 LogFunc(("IoCreateSymbolicLink failed with rcNt=%#x!\n", rcNt));
1680 IoDeleteDevice(pDeviceObject);
1681 }
1682 else
1683 LogFunc(("IoCreateDevice failed with rcNt=%#x!\n", rcNt));
1684
1685 LogFunc(("Returning with rcNt=%#x\n", rcNt));
1686 return rcNt;
1687}
1688
1689
1690/**
1691 * Irp completion routine for PnP Irps we send.
1692 *
1693 * @returns NT status code.
1694 * @param pDevObj Device object.
1695 * @param pIrp Request packet.
1696 * @param pEvent Semaphore.
1697 */
1698static NTSTATUS vgdrvNt5PlusPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
1699{
1700 RT_NOREF2(pDevObj, pIrp);
1701 KeSetEvent(pEvent, 0, FALSE);
1702 return STATUS_MORE_PROCESSING_REQUIRED;
1703}
1704
1705
1706/**
1707 * Helper to send a PnP IRP and wait until it's done.
1708 *
1709 * @returns NT status code.
1710 * @param pDevObj Device object.
1711 * @param pIrp Request packet.
1712 * @param fStrict When set, returns an error if the IRP gives an error.
1713 */
1714static NTSTATUS vgdrvNt5PlusPnPSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
1715{
1716 KEVENT Event;
1717
1718 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1719
1720 IoCopyCurrentIrpStackLocationToNext(pIrp);
1721 IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vgdrvNt5PlusPnpIrpComplete, &Event, TRUE, TRUE, TRUE);
1722
1723 NTSTATUS rcNt = IoCallDriver(pDevObj, pIrp);
1724 if (rcNt == STATUS_PENDING)
1725 {
1726 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1727 rcNt = pIrp->IoStatus.Status;
1728 }
1729
1730 if ( !fStrict
1731 && (rcNt == STATUS_NOT_SUPPORTED || rcNt == STATUS_INVALID_DEVICE_REQUEST))
1732 {
1733 rcNt = STATUS_SUCCESS;
1734 }
1735
1736 Log(("vgdrvNt5PlusPnPSendIrpSynchronously: Returning %#x\n", rcNt));
1737 return rcNt;
1738}
1739
1740
1741/**
1742 * Deletes the device hardware resources.
1743 *
1744 * Used during removal, stopping and legacy module unloading.
1745 *
1746 * @param pDevExt The device extension.
1747 */
1748static void vgdrvNtDeleteDeviceResources(PVBOXGUESTDEVEXTWIN pDevExt)
1749{
1750 if (pDevExt->pInterruptObject)
1751 {
1752 IoDisconnectInterrupt(pDevExt->pInterruptObject);
1753 pDevExt->pInterruptObject = NULL;
1754 }
1755 pDevExt->pPowerStateRequest = NULL; /* Will be deleted by the following call. */
1756 if (pDevExt->Core.uInitState == VBOXGUESTDEVEXT_INIT_STATE_RESOURCES)
1757 VGDrvCommonDeleteDevExtResources(&pDevExt->Core);
1758 vgdrvNtUnmapVMMDevMmioReq(pDevExt);
1759 vgdrvNtUnmapVMMDevMemory(pDevExt);
1760}
1761
1762
1763/**
1764 * Deletes the device extension fundament and unlinks the device
1765 *
1766 * Used during removal and legacy module unloading. Must have called
1767 * vgdrvNtDeleteDeviceResources.
1768 *
1769 * @param pDevObj Device object.
1770 * @param pDevExt The device extension.
1771 */
1772static void vgdrvNtDeleteDeviceFundamentAndUnlink(PDEVICE_OBJECT pDevObj, PVBOXGUESTDEVEXTWIN pDevExt)
1773{
1774 /*
1775 * Delete the remainder of the device extension.
1776 */
1777 vgdrvNtDeleteDevExtFundament(pDevExt);
1778
1779 /*
1780 * Delete the DOS symlink to the device and finally the device itself.
1781 */
1782 UNICODE_STRING DosName;
1783 RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
1784 IoDeleteSymbolicLink(&DosName);
1785
1786 Log(("vgdrvNtDeleteDeviceFundamentAndUnlink: Deleting device ...\n"));
1787 IoDeleteDevice(pDevObj);
1788}
1789
1790
1791/**
1792 * Checks if the device is idle.
1793 * @returns STATUS_SUCCESS if idle, STATUS_UNSUCCESSFUL if busy.
1794 * @param pDevExt The device extension.
1795 * @param pszQueryNm The query name.
1796 */
1797static NTSTATUS vgdrvNtCheckIdle(PVBOXGUESTDEVEXTWIN pDevExt, const char *pszQueryNm)
1798{
1799 uint32_t cSessions = pDevExt->Core.cSessions;
1800 if (cSessions == 0)
1801 return STATUS_SUCCESS;
1802 LogRel(("vgdrvNtCheckIdle/%s: cSessions=%d\n", pszQueryNm, cSessions));
1803 return STATUS_UNSUCCESSFUL;
1804}
1805
1806
1807/**
1808 * PnP Request handler.
1809 *
1810 * @param pDevObj Device object.
1811 * @param pIrp Request packet.
1812 */
1813static NTSTATUS NTAPI vgdrvNtNt5PlusPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1814{
1815 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
1816 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1817
1818#ifdef LOG_ENABLED
1819 static char const * const s_apszFnctName[] =
1820 {
1821 "IRP_MN_START_DEVICE",
1822 "IRP_MN_QUERY_REMOVE_DEVICE",
1823 "IRP_MN_REMOVE_DEVICE",
1824 "IRP_MN_CANCEL_REMOVE_DEVICE",
1825 "IRP_MN_STOP_DEVICE",
1826 "IRP_MN_QUERY_STOP_DEVICE",
1827 "IRP_MN_CANCEL_STOP_DEVICE",
1828 "IRP_MN_QUERY_DEVICE_RELATIONS",
1829 "IRP_MN_QUERY_INTERFACE",
1830 "IRP_MN_QUERY_CAPABILITIES",
1831 "IRP_MN_QUERY_RESOURCES",
1832 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
1833 "IRP_MN_QUERY_DEVICE_TEXT",
1834 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
1835 "IRP_MN_0xE",
1836 "IRP_MN_READ_CONFIG",
1837 "IRP_MN_WRITE_CONFIG",
1838 "IRP_MN_EJECT",
1839 "IRP_MN_SET_LOCK",
1840 "IRP_MN_QUERY_ID",
1841 "IRP_MN_QUERY_PNP_DEVICE_STATE",
1842 "IRP_MN_QUERY_BUS_INFORMATION",
1843 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
1844 "IRP_MN_SURPRISE_REMOVAL",
1845 };
1846 Log(("vgdrvNtNt5PlusPnP: MinorFunction: %s\n",
1847 pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName) ? s_apszFnctName[pStack->MinorFunction] : "Unknown"));
1848#endif
1849
1850 NTSTATUS rc = STATUS_SUCCESS;
1851 uint8_t bMinorFunction = pStack->MinorFunction;
1852 switch (bMinorFunction)
1853 {
1854 case IRP_MN_START_DEVICE:
1855 {
1856 Log(("vgdrvNtNt5PlusPnP: START_DEVICE\n"));
1857
1858 /* This must be handled first by the lower driver. */
1859 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
1860 if ( NT_SUCCESS(rc)
1861 && NT_SUCCESS(pIrp->IoStatus.Status))
1862 {
1863 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
1864 pStack->Parameters.StartDevice.AllocatedResources));
1865 if (pStack->Parameters.StartDevice.AllocatedResources)
1866 {
1867 rc = vgdrvNtSetupDevice(pDevExt, pDevObj, pIrp, NULL, NULL);
1868 if (NT_SUCCESS(rc))
1869 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: success\n"));
1870 else
1871 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: vgdrvNtSetupDevice failed: %#x\n", rc));
1872 }
1873 else
1874 {
1875 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
1876 pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL));
1877 rc = STATUS_UNSUCCESSFUL;
1878 }
1879 }
1880 else
1881 Log(("vgdrvNtNt5PlusPnP: START_DEVICE: vgdrvNt5PlusPnPSendIrpSynchronously failed: %#x + %#x\n",
1882 rc, pIrp->IoStatus.Status));
1883
1884 pIrp->IoStatus.Status = rc;
1885 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1886 return rc;
1887 }
1888
1889
1890 /*
1891 * Sent before removing the device and/or driver.
1892 */
1893 case IRP_MN_QUERY_REMOVE_DEVICE:
1894 {
1895 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE\n"));
1896
1897 RTCritSectRwEnterExcl(&pDevExt->SessionCreateCritSect);
1898#ifdef VBOX_REBOOT_ON_UNINSTALL
1899 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
1900 rc = STATUS_UNSUCCESSFUL;
1901#endif
1902 if (NT_SUCCESS(rc))
1903 rc = vgdrvNtCheckIdle(pDevExt, "QUERY_REMOVE_DEVICE");
1904 if (NT_SUCCESS(rc))
1905 {
1906 pDevExt->enmDevState = VGDRVNTDEVSTATE_PENDINGREMOVE;
1907 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
1908
1909 /* This IRP passed down to lower driver. */
1910 pIrp->IoStatus.Status = STATUS_SUCCESS;
1911
1912 IoSkipCurrentIrpStackLocation(pIrp);
1913 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1914 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
1915
1916 /* We must not do anything the IRP after doing IoSkip & CallDriver
1917 since the driver below us will complete (or already have completed) the IRP.
1918 I.e. just return the status we got from IoCallDriver */
1919 }
1920 else
1921 {
1922 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
1923 pIrp->IoStatus.Status = rc;
1924 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1925 }
1926
1927 Log(("vgdrvNtNt5PlusPnP: QUERY_REMOVE_DEVICE: Returning with rc = 0x%x\n", rc));
1928 return rc;
1929 }
1930
1931 /*
1932 * Cancels a pending remove, IRP_MN_QUERY_REMOVE_DEVICE.
1933 * We only have to revert the state.
1934 */
1935 case IRP_MN_CANCEL_REMOVE_DEVICE:
1936 {
1937 Log(("vgdrvNtNt5PlusPnP: CANCEL_REMOVE_DEVICE\n"));
1938
1939 /* This must be handled first by the lower driver. */
1940 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
1941 if ( NT_SUCCESS(rc)
1942 && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGREMOVE)
1943 {
1944 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
1945 pDevExt->enmDevState = pDevExt->enmPrevDevState;
1946 }
1947
1948 /* Complete the IRP. */
1949 pIrp->IoStatus.Status = rc;
1950 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1951 return rc;
1952 }
1953
1954 /*
1955 * We do nothing here actually, esp. since this request is not expected for VBoxGuest.
1956 * The cleanup will be done in IRP_MN_REMOVE_DEVICE, which follows this call.
1957 */
1958 case IRP_MN_SURPRISE_REMOVAL:
1959 {
1960 Log(("vgdrvNtNt5PlusPnP: IRP_MN_SURPRISE_REMOVAL\n"));
1961 pDevExt->enmDevState = VGDRVNTDEVSTATE_SURPRISEREMOVED;
1962 LogRel(("VBoxGuest: unexpected device removal\n"));
1963
1964 /* Pass to the lower driver. */
1965 pIrp->IoStatus.Status = STATUS_SUCCESS;
1966
1967 IoSkipCurrentIrpStackLocation(pIrp);
1968 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1969
1970 /* Do not complete the IRP. */
1971 return rc;
1972 }
1973
1974 /*
1975 * Device and/or driver removal. Destroy everything.
1976 */
1977 case IRP_MN_REMOVE_DEVICE:
1978 {
1979 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE\n"));
1980 pDevExt->enmDevState = VGDRVNTDEVSTATE_REMOVED;
1981
1982 /*
1983 * Disconnect interrupts and delete all hardware resources.
1984 * Note! This may already have been done if we're STOPPED already, if that's a possibility.
1985 */
1986 vgdrvNtDeleteDeviceResources(pDevExt);
1987
1988 /*
1989 * We need to send the remove down the stack before we detach, but we don't need
1990 * to wait for the completion of this operation (nor register a completion routine).
1991 */
1992 pIrp->IoStatus.Status = STATUS_SUCCESS;
1993
1994 IoSkipCurrentIrpStackLocation(pIrp);
1995 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
1996 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
1997
1998 IoDetachDevice(pDevExt->pNextLowerDriver);
1999 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Removing device ...\n"));
2000
2001 /*
2002 * Delete the remainder of the device extension data, unlink it from the namespace and delete it.
2003 */
2004 vgdrvNtDeleteDeviceFundamentAndUnlink(pDevObj, pDevExt);
2005
2006 pDevObj = NULL; /* invalid */
2007 pDevExt = NULL; /* invalid */
2008
2009 Log(("vgdrvNtNt5PlusPnP: REMOVE_DEVICE: Device removed!\n"));
2010 return rc; /* Propagating rc from IoCallDriver. */
2011 }
2012
2013
2014 /*
2015 * Sent before stopping the device/driver to check whether it is okay to do so.
2016 */
2017 case IRP_MN_QUERY_STOP_DEVICE:
2018 {
2019 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE\n"));
2020 RTCritSectRwEnterExcl(&pDevExt->SessionCreateCritSect);
2021 rc = vgdrvNtCheckIdle(pDevExt, "QUERY_STOP_DEVICE");
2022 if (NT_SUCCESS(rc))
2023 {
2024 pDevExt->enmPrevDevState = pDevExt->enmDevState;
2025 pDevExt->enmDevState = VGDRVNTDEVSTATE_PENDINGSTOP;
2026 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
2027
2028 /* This IRP passed down to lower driver. */
2029 pIrp->IoStatus.Status = STATUS_SUCCESS;
2030
2031 IoSkipCurrentIrpStackLocation(pIrp);
2032
2033 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2034 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
2035
2036 /* we must not do anything with the IRP after doing IoSkip & CallDriver since the
2037 driver below us will complete (or already have completed) the IRP. I.e. just
2038 return the status we got from IoCallDriver. */
2039 }
2040 else
2041 {
2042 RTCritSectRwLeaveExcl(&pDevExt->SessionCreateCritSect);
2043 pIrp->IoStatus.Status = rc;
2044 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2045 }
2046
2047 Log(("vgdrvNtNt5PlusPnP: QUERY_STOP_DEVICE: Returning with rc = 0x%x\n", rc));
2048 return rc;
2049 }
2050
2051 /*
2052 * Cancels a pending remove, IRP_MN_QUERY_STOP_DEVICE.
2053 * We only have to revert the state.
2054 */
2055 case IRP_MN_CANCEL_STOP_DEVICE:
2056 {
2057 Log(("vgdrvNtNt5PlusPnP: CANCEL_STOP_DEVICE\n"));
2058
2059 /* This must be handled first by the lower driver. */
2060 rc = vgdrvNt5PlusPnPSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
2061 if ( NT_SUCCESS(rc)
2062 && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGSTOP)
2063 {
2064 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
2065 pDevExt->enmDevState = pDevExt->enmPrevDevState;
2066 }
2067
2068 /* Complete the IRP. */
2069 pIrp->IoStatus.Status = rc;
2070 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2071 return rc;
2072 }
2073
2074 /*
2075 * Stop the device.
2076 */
2077 case IRP_MN_STOP_DEVICE:
2078 {
2079 Log(("vgdrvNtNt5PlusPnP: STOP_DEVICE\n"));
2080 pDevExt->enmDevState = VGDRVNTDEVSTATE_STOPPED;
2081
2082 /*
2083 * Release the hardware resources.
2084 */
2085 vgdrvNtDeleteDeviceResources(pDevExt);
2086
2087 /*
2088 * Pass the request to the lower driver.
2089 */
2090 pIrp->IoStatus.Status = STATUS_SUCCESS;
2091 IoSkipCurrentIrpStackLocation(pIrp);
2092 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2093 Log(("vgdrvNtNt5PlusPnP: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
2094 return rc;
2095 }
2096
2097 default:
2098 {
2099 IoSkipCurrentIrpStackLocation(pIrp);
2100 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2101 Log(("vgdrvNtNt5PlusPnP: Unknown request %#x: Lower driver replied: %x\n", bMinorFunction, rc));
2102 return rc;
2103 }
2104 }
2105}
2106
2107
2108/**
2109 * Handle the power completion event.
2110 *
2111 * @returns NT status code.
2112 * @param pDevObj Targetted device object.
2113 * @param pIrp IO request packet.
2114 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
2115 */
2116static NTSTATUS vgdrvNtNt5PlusPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
2117{
2118#ifdef VBOX_STRICT
2119 RT_NOREF1(pDevObj);
2120 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pContext;
2121 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
2122
2123 Assert(pDevExt);
2124
2125 if (pIrpSp)
2126 {
2127 Assert(pIrpSp->MajorFunction == IRP_MJ_POWER);
2128 if (NT_SUCCESS(pIrp->IoStatus.Status))
2129 {
2130 switch (pIrpSp->MinorFunction)
2131 {
2132 case IRP_MN_SET_POWER:
2133 switch (pIrpSp->Parameters.Power.Type)
2134 {
2135 case DevicePowerState:
2136 switch (pIrpSp->Parameters.Power.State.DeviceState)
2137 {
2138 case PowerDeviceD0:
2139 break;
2140 default: /* Shut up MSC */
2141 break;
2142 }
2143 break;
2144 default: /* Shut up MSC */
2145 break;
2146 }
2147 break;
2148 }
2149 }
2150 }
2151#else
2152 RT_NOREF3(pDevObj, pIrp, pContext);
2153#endif
2154
2155 return STATUS_SUCCESS;
2156}
2157
2158
2159/**
2160 * Handle the Power requests.
2161 *
2162 * @returns NT status code
2163 * @param pDevObj device object
2164 * @param pIrp IRP
2165 */
2166static NTSTATUS NTAPI vgdrvNtNt5PlusPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2167{
2168 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2169 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2170 POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
2171 POWER_STATE PowerState = pStack->Parameters.Power.State;
2172 POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
2173
2174 Log(("vgdrvNtNt5PlusPower:\n"));
2175
2176 switch (pStack->MinorFunction)
2177 {
2178 case IRP_MN_SET_POWER:
2179 {
2180 Log(("vgdrvNtNt5PlusPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
2181 switch (enmPowerType)
2182 {
2183 case SystemPowerState:
2184 {
2185 Log(("vgdrvNtNt5PlusPower: SystemPowerState, action = %d, state = %d/%d\n",
2186 enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
2187
2188 switch (enmPowerAction)
2189 {
2190 case PowerActionSleep:
2191
2192 /* System now is in a working state. */
2193 if (PowerState.SystemState == PowerSystemWorking)
2194 {
2195 if ( pDevExt
2196 && pDevExt->enmLastSystemPowerAction == PowerActionHibernate)
2197 {
2198 Log(("vgdrvNtNt5PlusPower: Returning from hibernation!\n"));
2199 int rc = VGDrvCommonReinitDevExtAfterHibernation(&pDevExt->Core,
2200 vgdrvNtVersionToOSType(g_enmVGDrvNtVer));
2201 if (RT_FAILURE(rc))
2202 Log(("vgdrvNtNt5PlusPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
2203 }
2204 }
2205 break;
2206
2207 case PowerActionShutdownReset:
2208 {
2209 Log(("vgdrvNtNt5PlusPower: Power action reset!\n"));
2210
2211 /* Tell the VMM that we no longer support mouse pointer integration. */
2212 VMMDevReqMouseStatus *pReq = NULL;
2213 int vrc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus),
2214 VMMDevReq_SetMouseStatus);
2215 if (RT_SUCCESS(vrc))
2216 {
2217 pReq->mouseFeatures = 0;
2218 pReq->pointerXPos = 0;
2219 pReq->pointerYPos = 0;
2220
2221 vrc = VbglR0GRPerform(&pReq->header);
2222 if (RT_FAILURE(vrc))
2223 {
2224 Log(("vgdrvNtNt5PlusPower: error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
2225 }
2226
2227 VbglR0GRFree(&pReq->header);
2228 }
2229
2230 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
2231 * power action and would assert/crash when we already cleaned up all the stuff! */
2232 break;
2233 }
2234
2235 case PowerActionShutdown:
2236 case PowerActionShutdownOff:
2237 {
2238 Log(("vgdrvNtNt5PlusPower: Power action shutdown!\n"));
2239 if (PowerState.SystemState >= PowerSystemShutdown)
2240 {
2241 Log(("vgdrvNtNt5PlusPower: Telling the VMMDev to close the VM ...\n"));
2242
2243 VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
2244 int vrc = VERR_NOT_IMPLEMENTED;
2245 if (pReq)
2246 {
2247 pReq->header.requestType = VMMDevReq_SetPowerStatus;
2248 pReq->powerState = VMMDevPowerState_PowerOff;
2249
2250 vrc = VbglR0GRPerform(&pReq->header);
2251 }
2252 if (RT_FAILURE(vrc))
2253 Log(("vgdrvNtNt5PlusPower: Error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
2254
2255 /* No need to do cleanup here; at this point we should've been
2256 * turned off by VMMDev already! */
2257 }
2258 break;
2259 }
2260
2261 case PowerActionHibernate:
2262 Log(("vgdrvNtNt5PlusPower: Power action hibernate!\n"));
2263 break;
2264
2265 case PowerActionWarmEject:
2266 Log(("vgdrvNtNt5PlusPower: PowerActionWarmEject!\n"));
2267 break;
2268
2269 default:
2270 Log(("vgdrvNtNt5PlusPower: %d\n", enmPowerAction));
2271 break;
2272 }
2273
2274 /*
2275 * Save the current system power action for later use.
2276 * This becomes handy when we return from hibernation for example.
2277 */
2278 if (pDevExt)
2279 pDevExt->enmLastSystemPowerAction = enmPowerAction;
2280
2281 break;
2282 }
2283 default:
2284 break;
2285 }
2286 break;
2287 }
2288 default:
2289 break;
2290 }
2291
2292 /*
2293 * Whether we are completing or relaying this power IRP,
2294 * we must call PoStartNextPowerIrp.
2295 */
2296 g_pfnPoStartNextPowerIrp(pIrp);
2297
2298 /*
2299 * Send the IRP down the driver stack, using PoCallDriver
2300 * (not IoCallDriver, as for non-power irps).
2301 */
2302 IoCopyCurrentIrpStackLocationToNext(pIrp);
2303 IoSetCompletionRoutine(pIrp,
2304 vgdrvNtNt5PlusPowerComplete,
2305 (PVOID)pDevExt,
2306 TRUE,
2307 TRUE,
2308 TRUE);
2309 return g_pfnPoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2310}
2311
2312
2313/**
2314 * IRP_MJ_SYSTEM_CONTROL handler.
2315 *
2316 * @returns NT status code
2317 * @param pDevObj Device object.
2318 * @param pIrp IRP.
2319 */
2320static NTSTATUS NTAPI vgdrvNtNt5PlusSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2321{
2322 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2323
2324 LogFlowFuncEnter();
2325
2326 /* Always pass it on to the next driver. */
2327 IoSkipCurrentIrpStackLocation(pIrp);
2328
2329 return IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
2330}
2331
2332
2333/**
2334 * Unload the driver.
2335 *
2336 * @param pDrvObj Driver object.
2337 */
2338static void NTAPI vgdrvNtUnload(PDRIVER_OBJECT pDrvObj)
2339{
2340 LogFlowFuncEnter();
2341
2342#ifdef TARGET_NT4
2343 /*
2344 * We need to destroy the device object here on NT4 and earlier.
2345 */
2346 PDEVICE_OBJECT pDevObj = pDrvObj->DeviceObject;
2347 if (pDevObj)
2348 {
2349 if (g_enmVGDrvNtVer <= VGDRVNTVER_WINNT4)
2350 {
2351 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2352 AssertPtr(pDevExt);
2353 AssertMsg(pDevExt->Core.uInitState == VBOXGUESTDEVEXT_INIT_STATE_RESOURCES,
2354 ("uInitState=%#x\n", pDevExt->Core.uInitState));
2355
2356 vgdrvNtDeleteDeviceResources(pDevExt);
2357 vgdrvNtDeleteDeviceFundamentAndUnlink(pDevObj, pDevExt);
2358 }
2359 }
2360#else /* !TARGET_NT4 */
2361 /*
2362 * On a PnP driver this routine will be called after IRP_MN_REMOVE_DEVICE
2363 * where we already did the cleanup, so don't do anything here (yet).
2364 */
2365 RT_NOREF1(pDrvObj);
2366#endif /* !TARGET_NT4 */
2367
2368 VGDrvCommonDestroyLoggers();
2369 RTR0Term();
2370
2371 /*
2372 * Finally deregister the bugcheck callback. Do it late to catch trouble in RTR0Term.
2373 */
2374 if (g_fBugCheckCallbackRegistered)
2375 {
2376 g_pfnKeDeregisterBugCheckCallback(&g_BugCheckCallbackRec);
2377 g_fBugCheckCallbackRegistered = false;
2378 }
2379}
2380
2381
2382/**
2383 * For simplifying request completion into a simple return statement, extended
2384 * version.
2385 *
2386 * @returns rcNt
2387 * @param rcNt The status code.
2388 * @param uInfo Extra info value.
2389 * @param pIrp The IRP.
2390 */
2391DECLINLINE(NTSTATUS) vgdrvNtCompleteRequestEx(NTSTATUS rcNt, ULONG_PTR uInfo, PIRP pIrp)
2392{
2393 pIrp->IoStatus.Status = rcNt;
2394 pIrp->IoStatus.Information = uInfo;
2395 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2396 return rcNt;
2397}
2398
2399
2400/**
2401 * For simplifying request completion into a simple return statement.
2402 *
2403 * @returns rcNt
2404 * @param rcNt The status code.
2405 * @param pIrp The IRP.
2406 */
2407DECLINLINE(NTSTATUS) vgdrvNtCompleteRequest(NTSTATUS rcNt, PIRP pIrp)
2408{
2409 return vgdrvNtCompleteRequestEx(rcNt, 0 /*uInfo*/, pIrp);
2410}
2411
2412
2413/**
2414 * Checks if NT authority rev 1 SID (SECURITY_NT_AUTHORITY).
2415 *
2416 * @returns true / false.
2417 * @param pSid The SID to check.
2418 */
2419DECLINLINE(bool) vgdrvNtIsSidNtAuth(struct _SID const *pSid)
2420{
2421 return pSid != NULL
2422 && pSid->Revision == 1
2423 && pSid->IdentifierAuthority.Value[5] == 5
2424 && pSid->IdentifierAuthority.Value[4] == 0
2425 && pSid->IdentifierAuthority.Value[3] == 0
2426 && pSid->IdentifierAuthority.Value[2] == 0
2427 && pSid->IdentifierAuthority.Value[1] == 0
2428 && pSid->IdentifierAuthority.Value[0] == 0;
2429}
2430
2431
2432/**
2433 * Matches SID with local system user (S-1-5-18 / SECURITY_LOCAL_SYSTEM_RID).
2434 */
2435DECLINLINE(bool) vgdrvNtIsSidLocalSystemUser(SID const *pSid)
2436{
2437 return vgdrvNtIsSidNtAuth(pSid)
2438 && pSid->SubAuthorityCount == 1
2439 && pSid->SubAuthority[0] == SECURITY_LOCAL_SYSTEM_RID;
2440}
2441
2442
2443/**
2444 * Matches SID with NT system admin user (S-1-5-*-500 / DOMAIN_USER_RID_ADMIN).
2445 */
2446DECLINLINE(bool) vgdrvNtIsSidAdminUser(SID const *pSid)
2447{
2448 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2449 return vgdrvNtIsSidNtAuth(pSid)
2450 && pSid->SubAuthorityCount >= 2
2451 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2452 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_USER_RID_ADMIN;
2453}
2454
2455
2456/**
2457 * Matches SID with NT system guest user (S-1-5-*-501 / DOMAIN_USER_RID_GUEST).
2458 */
2459DECLINLINE(bool) vgdrvNtIsSidGuestUser(SID const *pSid)
2460{
2461 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2462 return vgdrvNtIsSidNtAuth(pSid)
2463 && pSid->SubAuthorityCount >= 2
2464 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2465 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_USER_RID_GUEST;
2466}
2467
2468
2469/**
2470 * Matches SID with NT system admins group (S-1-5-32-544, S-1-5-*-512).
2471 */
2472DECLINLINE(bool) vgdrvNtIsSidAdminsGroup(SID const *pSid)
2473{
2474 return vgdrvNtIsSidNtAuth(pSid)
2475 && ( ( pSid->SubAuthorityCount == 2
2476 && pSid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID
2477 && pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_ADMINS)
2478#if 0
2479 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2480 || ( pSid->SubAuthorityCount >= 2
2481 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2482 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_GROUP_RID_ADMINS)
2483#endif
2484 );
2485}
2486
2487
2488/**
2489 * Matches SID with NT system users group (S-1-5-32-545, S-1-5-32-547, S-1-5-*-512).
2490 */
2491DECLINLINE(bool) vgdrvNtIsSidUsersGroup(SID const *pSid)
2492{
2493 return vgdrvNtIsSidNtAuth(pSid)
2494 && ( ( pSid->SubAuthorityCount == 2
2495 && pSid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID
2496 && ( pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_USERS
2497 || pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_POWER_USERS) )
2498#if 0
2499 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2500 || ( pSid->SubAuthorityCount >= 2
2501 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2502 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_GROUP_RID_USERS)
2503#endif
2504 );
2505}
2506
2507
2508/**
2509 * Matches SID with NT system guests group (S-1-5-32-546, S-1-5-*-512).
2510 */
2511DECLINLINE(bool) vgdrvNtIsSidGuestsGroup(SID const *pSid)
2512{
2513 return vgdrvNtIsSidNtAuth(pSid)
2514 && ( ( pSid->SubAuthorityCount == 2
2515 && pSid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID
2516 && pSid->SubAuthority[1] == DOMAIN_ALIAS_RID_GUESTS)
2517#if 0
2518 /** @todo restrict to SECURITY_NT_NON_UNIQUE? */
2519 || ( pSid->SubAuthorityCount >= 2
2520 && pSid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES
2521 && pSid->SubAuthority[pSid->SubAuthorityCount - 1] == DOMAIN_GROUP_RID_GUESTS)
2522#endif
2523 );
2524}
2525
2526
2527/**
2528 * Checks if local authority rev 1 SID (SECURITY_LOCAL_SID_AUTHORITY).
2529 *
2530 * @returns true / false.
2531 * @param pSid The SID to check.
2532 */
2533DECLINLINE(bool) vgdrvNtIsSidLocalAuth(struct _SID const *pSid)
2534{
2535 return pSid != NULL
2536 && pSid->Revision == 1
2537 && pSid->IdentifierAuthority.Value[5] == 2
2538 && pSid->IdentifierAuthority.Value[4] == 0
2539 && pSid->IdentifierAuthority.Value[3] == 0
2540 && pSid->IdentifierAuthority.Value[2] == 0
2541 && pSid->IdentifierAuthority.Value[1] == 0
2542 && pSid->IdentifierAuthority.Value[0] == 0;
2543}
2544
2545
2546/**
2547 * Matches SID with console logon group (S-1-2-1 / SECURITY_LOCAL_LOGON_RID).
2548 */
2549DECLINLINE(bool) vgdrvNtIsSidConsoleLogonGroup(SID const *pSid)
2550{
2551 return vgdrvNtIsSidLocalAuth(pSid)
2552 && pSid->SubAuthorityCount == 1
2553 && pSid->SubAuthority[0] == SECURITY_LOCAL_LOGON_RID;
2554}
2555
2556
2557/**
2558 * Checks if mandatory label authority rev 1 SID (SECURITY_MANDATORY_LABEL_AUTHORITY).
2559 *
2560 * @returns true / false.
2561 * @param pSid The SID to check.
2562 */
2563DECLINLINE(bool) vgdrvNtIsSidMandatoryLabelAuth(struct _SID const *pSid)
2564{
2565 return pSid != NULL
2566 && pSid->Revision == 1
2567 && pSid->IdentifierAuthority.Value[5] == 16
2568 && pSid->IdentifierAuthority.Value[4] == 0
2569 && pSid->IdentifierAuthority.Value[3] == 0
2570 && pSid->IdentifierAuthority.Value[2] == 0
2571 && pSid->IdentifierAuthority.Value[1] == 0
2572 && pSid->IdentifierAuthority.Value[0] == 0;
2573}
2574
2575
2576#ifdef LOG_ENABLED
2577/** Format an SID for logging. */
2578static const char *vgdrvNtFormatSid(char *pszBuf, size_t cbBuf, struct _SID const *pSid)
2579{
2580 uint64_t uAuth = RT_MAKE_U64_FROM_U8(pSid->IdentifierAuthority.Value[5], pSid->IdentifierAuthority.Value[4],
2581 pSid->IdentifierAuthority.Value[3], pSid->IdentifierAuthority.Value[2],
2582 pSid->IdentifierAuthority.Value[1], pSid->IdentifierAuthority.Value[0],
2583 0, 0);
2584 ssize_t offCur = RTStrPrintf2(pszBuf, cbBuf, "S-%u-%RU64", pSid->Revision, uAuth);
2585 ULONG const *puSubAuth = &pSid->SubAuthority[0];
2586 unsigned cSubAuths = pSid->SubAuthorityCount;
2587 while (cSubAuths > 0 && (size_t)offCur < cbBuf)
2588 {
2589 ssize_t cchThis = RTStrPrintf2(&pszBuf[offCur], cbBuf - (size_t)offCur, "-%u", *puSubAuth);
2590 if (cchThis > 0)
2591 {
2592 offCur += cchThis;
2593 puSubAuth++;
2594 cSubAuths--;
2595 }
2596 else
2597 {
2598 Assert(cbBuf >= 5);
2599 pszBuf[cbBuf - 4] = '.';
2600 pszBuf[cbBuf - 3] = '.';
2601 pszBuf[cbBuf - 2] = '.';
2602 pszBuf[cbBuf - 1] = '\0';
2603 break;
2604 }
2605 }
2606 return pszBuf;
2607}
2608#endif
2609
2610
2611/**
2612 * Calculate requestor flags for the current process.
2613 *
2614 * ASSUMES vgdrvNtCreate is executed in the context of the process and thread
2615 * doing the NtOpenFile call.
2616 *
2617 * @returns VMMDEV_REQUESTOR_XXX
2618 */
2619static uint32_t vgdrvNtCalcRequestorFlags(void)
2620{
2621 uint32_t fRequestor = VMMDEV_REQUESTOR_USERMODE
2622 | VMMDEV_REQUESTOR_USR_NOT_GIVEN
2623 | VMMDEV_REQUESTOR_CON_DONT_KNOW
2624 | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN
2625 | VMMDEV_REQUESTOR_NO_USER_DEVICE;
2626 HANDLE hToken = NULL;
2627 NTSTATUS rcNt = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken);
2628 if (NT_SUCCESS(rcNt))
2629 {
2630 union
2631 {
2632 TOKEN_USER CurUser;
2633 TOKEN_GROUPS CurGroups;
2634 uint8_t abPadding[256];
2635 } Buf;
2636#ifdef LOG_ENABLED
2637 char szSid[200];
2638#endif
2639
2640 /*
2641 * Get the user SID and see if it's a standard one.
2642 */
2643 RT_ZERO(Buf.CurUser);
2644 ULONG cbReturned = 0;
2645 rcNt = ZwQueryInformationToken(hToken, TokenUser, &Buf.CurUser, sizeof(Buf), &cbReturned);
2646 if (NT_SUCCESS(rcNt))
2647 {
2648 struct _SID const *pSid = (struct _SID const *)Buf.CurUser.User.Sid;
2649 Log5(("vgdrvNtCalcRequestorFlags: TokenUser: %#010x %s\n",
2650 Buf.CurUser.User.Attributes, vgdrvNtFormatSid(szSid, sizeof(szSid), pSid)));
2651
2652 if (vgdrvNtIsSidLocalSystemUser(pSid))
2653 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_SYSTEM;
2654 else if (vgdrvNtIsSidAdminUser(pSid))
2655 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_ROOT;
2656 else if (vgdrvNtIsSidGuestUser(pSid))
2657 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_GUEST;
2658 }
2659 else
2660 LogRel(("vgdrvNtCalcRequestorFlags: TokenUser query failed: %#x\n", rcNt));
2661
2662 /*
2663 * Get the groups.
2664 */
2665 TOKEN_GROUPS *pCurGroupsFree = NULL;
2666 TOKEN_GROUPS *pCurGroups = &Buf.CurGroups;
2667 uint32_t cbCurGroups = sizeof(Buf);
2668 cbReturned = 0;
2669 RT_ZERO(Buf);
2670 rcNt = ZwQueryInformationToken(hToken, TokenGroups, pCurGroups, cbCurGroups, &cbReturned);
2671 if (rcNt == STATUS_BUFFER_TOO_SMALL)
2672 {
2673 uint32_t cTries = 8;
2674 do
2675 {
2676 RTMemTmpFree(pCurGroupsFree);
2677 if (cbCurGroups < cbReturned)
2678 cbCurGroups = RT_ALIGN_32(cbCurGroups + 32, 64);
2679 else
2680 cbCurGroups += 64;
2681 pCurGroupsFree = pCurGroups = (TOKEN_GROUPS *)RTMemTmpAllocZ(cbCurGroups);
2682 if (pCurGroupsFree)
2683 rcNt = ZwQueryInformationToken(hToken, TokenGroups, pCurGroups, cbCurGroups, &cbReturned);
2684 else
2685 rcNt = STATUS_NO_MEMORY;
2686 } while (rcNt == STATUS_BUFFER_TOO_SMALL && cTries-- > 0);
2687 }
2688 if (NT_SUCCESS(rcNt))
2689 {
2690 bool fGuestsMember = false;
2691 bool fUsersMember = false;
2692 if (g_enmVGDrvNtVer >= VGDRVNTVER_WIN7)
2693 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_CON_MASK) | VMMDEV_REQUESTOR_CON_NO;
2694
2695 for (uint32_t iGrp = 0; iGrp < pCurGroups->GroupCount; iGrp++)
2696 {
2697 uint32_t const fAttribs = pCurGroups->Groups[iGrp].Attributes;
2698 struct _SID const *pSid = (struct _SID const *)pCurGroups->Groups[iGrp].Sid;
2699 Log5(("vgdrvNtCalcRequestorFlags: TokenGroups[%u]: %#10x %s\n",
2700 iGrp, fAttribs, vgdrvNtFormatSid(szSid, sizeof(szSid), pSid)));
2701
2702 if ( (fAttribs & SE_GROUP_INTEGRITY_ENABLED)
2703 && vgdrvNtIsSidMandatoryLabelAuth(pSid)
2704 && pSid->SubAuthorityCount == 1
2705 && (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_NOT_GIVEN)
2706 {
2707 fRequestor &= ~VMMDEV_REQUESTOR_TRUST_MASK;
2708 if (pSid->SubAuthority[0] < SECURITY_MANDATORY_LOW_RID)
2709 fRequestor |= VMMDEV_REQUESTOR_TRUST_UNTRUSTED;
2710 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_MEDIUM_RID)
2711 fRequestor |= VMMDEV_REQUESTOR_TRUST_LOW;
2712 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_MEDIUM_PLUS_RID)
2713 fRequestor |= VMMDEV_REQUESTOR_TRUST_MEDIUM;
2714 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_HIGH_RID)
2715 fRequestor |= VMMDEV_REQUESTOR_TRUST_MEDIUM_PLUS;
2716 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_SYSTEM_RID)
2717 fRequestor |= VMMDEV_REQUESTOR_TRUST_HIGH;
2718 else if (pSid->SubAuthority[0] < SECURITY_MANDATORY_PROTECTED_PROCESS_RID)
2719 fRequestor |= VMMDEV_REQUESTOR_TRUST_SYSTEM;
2720 else
2721 fRequestor |= VMMDEV_REQUESTOR_TRUST_PROTECTED;
2722 Log5(("vgdrvNtCalcRequestorFlags: mandatory label %u: => %#x\n", pSid->SubAuthority[0], fRequestor));
2723 }
2724 else if ( (fAttribs & (SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_USE_FOR_DENY_ONLY))
2725 == (SE_GROUP_ENABLED | SE_GROUP_MANDATORY)
2726 && vgdrvNtIsSidConsoleLogonGroup(pSid))
2727 {
2728 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_CON_MASK) | VMMDEV_REQUESTOR_CON_YES;
2729 Log5(("vgdrvNtCalcRequestorFlags: console: => %#x\n", fRequestor));
2730 }
2731 else if ( (fAttribs & (SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_USE_FOR_DENY_ONLY))
2732 == (SE_GROUP_ENABLED | SE_GROUP_MANDATORY)
2733 && vgdrvNtIsSidNtAuth(pSid))
2734 {
2735 if (vgdrvNtIsSidAdminsGroup(pSid))
2736 {
2737 fRequestor |= VMMDEV_REQUESTOR_GRP_WHEEL;
2738 Log5(("vgdrvNtCalcRequestorFlags: admins group: => %#x\n", fRequestor));
2739 }
2740 else if (vgdrvNtIsSidUsersGroup(pSid))
2741 {
2742 Log5(("vgdrvNtCalcRequestorFlags: users group\n"));
2743 fUsersMember = true;
2744 }
2745 else if (vgdrvNtIsSidGuestsGroup(pSid))
2746 {
2747 Log5(("vgdrvNtCalcRequestorFlags: guests group\n"));
2748 fGuestsMember = true;
2749 }
2750 }
2751 }
2752 if ((fRequestor & VMMDEV_REQUESTOR_USR_MASK) == VMMDEV_REQUESTOR_USR_NOT_GIVEN)
2753 {
2754 if (fUsersMember)
2755 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_USER;
2756 else if (fGuestsMember)
2757 fRequestor = (fRequestor & ~VMMDEV_REQUESTOR_USR_MASK) | VMMDEV_REQUESTOR_USR_GUEST;
2758 }
2759 }
2760 else
2761 LogRel(("vgdrvNtCalcRequestorFlags: TokenGroups query failed: %#x\n", rcNt));
2762
2763 RTMemTmpFree(pCurGroupsFree);
2764 ZwClose(hToken);
2765
2766 /*
2767 * Determine whether we should set VMMDEV_REQUESTOR_USER_DEVICE or not.
2768 *
2769 * The purpose here is to differentiate VBoxService accesses
2770 * from VBoxTray and VBoxControl, as VBoxService should be allowed to
2771 * do more than the latter two. VBoxService normally runs under the
2772 * system account which is easily detected, but for debugging and
2773 * similar purposes we also allow an elevated admin to run it as well.
2774 */
2775 if ( (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_UNTRUSTED /* general paranoia wrt system account */
2776 || (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_LOW /* ditto */
2777 || (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_MEDIUM /* ditto */
2778 || !( (fRequestor & VMMDEV_REQUESTOR_USR_MASK) == VMMDEV_REQUESTOR_USR_SYSTEM
2779 || ( ( (fRequestor & VMMDEV_REQUESTOR_GRP_WHEEL)
2780 || (fRequestor & VMMDEV_REQUESTOR_USR_MASK) == VMMDEV_REQUESTOR_USR_ROOT)
2781 && ( (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) >= VMMDEV_REQUESTOR_TRUST_HIGH
2782 || (fRequestor & VMMDEV_REQUESTOR_TRUST_MASK) == VMMDEV_REQUESTOR_TRUST_NOT_GIVEN)) ))
2783 fRequestor |= VMMDEV_REQUESTOR_USER_DEVICE;
2784 }
2785 else
2786 {
2787 LogRel(("vgdrvNtCalcRequestorFlags: NtOpenProcessToken query failed: %#x\n", rcNt));
2788 fRequestor |= VMMDEV_REQUESTOR_USER_DEVICE;
2789 }
2790
2791 Log5(("vgdrvNtCalcRequestorFlags: returns %#x\n", fRequestor));
2792 return fRequestor;
2793}
2794
2795
2796/**
2797 * Create (i.e. Open) file entry point.
2798 *
2799 * @param pDevObj Device object.
2800 * @param pIrp Request packet.
2801 */
2802static NTSTATUS NTAPI vgdrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2803{
2804 Log(("vgdrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
2805 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2806 PFILE_OBJECT pFileObj = pStack->FileObject;
2807 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2808
2809 Assert(pFileObj->FsContext == NULL);
2810
2811 /*
2812 * We are not remotely similar to a directory...
2813 */
2814 NTSTATUS rcNt;
2815 if (!(pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE))
2816 {
2817 /*
2818 * Check the device state. We enter the critsect in shared mode to
2819 * prevent race with PnP system requests checking whether we're idle.
2820 */
2821 RTCritSectRwEnterShared(&pDevExt->SessionCreateCritSect);
2822 VGDRVNTDEVSTATE const enmDevState = pDevExt->enmDevState;
2823 if (enmDevState == VGDRVNTDEVSTATE_OPERATIONAL)
2824 {
2825 /*
2826 * Create a client session.
2827 */
2828 int rc;
2829 PVBOXGUESTSESSION pSession;
2830 if (pIrp->RequestorMode == KernelMode)
2831 rc = VGDrvCommonCreateKernelSession(&pDevExt->Core, &pSession);
2832 else
2833 rc = VGDrvCommonCreateUserSession(&pDevExt->Core, vgdrvNtCalcRequestorFlags(), &pSession);
2834 RTCritSectRwLeaveShared(&pDevExt->SessionCreateCritSect);
2835 if (RT_SUCCESS(rc))
2836 {
2837 pFileObj->FsContext = pSession;
2838 Log(("vgdrvNtCreate: Successfully created %s session %p (fRequestor=%#x)\n",
2839 pIrp->RequestorMode == KernelMode ? "kernel" : "user", pSession, pSession->fRequestor));
2840
2841 return vgdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
2842 }
2843
2844 /* Note. the IoStatus is completely ignored on error. */
2845 Log(("vgdrvNtCreate: Failed to create session: rc=%Rrc\n", rc));
2846 if (rc == VERR_NO_MEMORY)
2847 rcNt = STATUS_NO_MEMORY;
2848 else
2849 rcNt = STATUS_UNSUCCESSFUL;
2850 }
2851 else
2852 {
2853 RTCritSectRwLeaveShared(&pDevExt->SessionCreateCritSect);
2854 LogFlow(("vgdrvNtCreate: Failed. Device is not in 'working' state: %d\n", enmDevState));
2855 rcNt = STATUS_DEVICE_NOT_READY;
2856 }
2857 }
2858 else
2859 {
2860 LogFlow(("vgdrvNtCreate: Failed. FILE_DIRECTORY_FILE set\n"));
2861 rcNt = STATUS_NOT_A_DIRECTORY;
2862 }
2863 return vgdrvNtCompleteRequest(rcNt, pIrp);
2864}
2865
2866
2867/**
2868 * Close file entry point.
2869 *
2870 * @param pDevObj Device object.
2871 * @param pIrp Request packet.
2872 */
2873static NTSTATUS NTAPI vgdrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2874{
2875 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2876 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2877 PFILE_OBJECT pFileObj = pStack->FileObject;
2878
2879 LogFlowFunc(("pDevExt=0x%p, pFileObj=0x%p, FsContext=0x%p\n", pDevExt, pFileObj, pFileObj->FsContext));
2880
2881#ifdef VBOX_WITH_HGCM
2882 /* Close both, R0 and R3 sessions. */
2883 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFileObj->FsContext;
2884 if (pSession)
2885 VGDrvCommonCloseSession(&pDevExt->Core, pSession);
2886#endif
2887
2888 pFileObj->FsContext = NULL;
2889 pIrp->IoStatus.Information = 0;
2890 pIrp->IoStatus.Status = STATUS_SUCCESS;
2891 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
2892
2893 return STATUS_SUCCESS;
2894}
2895
2896
2897/**
2898 * Device I/O Control entry point.
2899 *
2900 * @param pDevObj Device object.
2901 * @param pIrp Request packet.
2902 */
2903NTSTATUS NTAPI vgdrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
2904{
2905 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
2906 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
2907 PVBOXGUESTSESSION pSession = pStack->FileObject ? (PVBOXGUESTSESSION)pStack->FileObject->FsContext : NULL;
2908
2909 if (!RT_VALID_PTR(pSession))
2910 return vgdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
2911
2912#if 0 /* No fast I/O controls defined yet. */
2913 /*
2914 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
2915 * the session and iCmd, and does not return anything.
2916 */
2917 if (pSession->fUnrestricted)
2918 {
2919 ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
2920 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
2921 || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
2922 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
2923 {
2924 int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
2925
2926 /* Complete the I/O request. */
2927 supdrvSessionRelease(pSession);
2928 return vgdrvNtCompleteRequest(RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER, pIrp);
2929 }
2930 }
2931#endif
2932
2933 return vgdrvNtDeviceControlSlow(&pDevExt->Core, pSession, pIrp, pStack);
2934}
2935
2936
2937/**
2938 * Device I/O Control entry point.
2939 *
2940 * @param pDevExt The device extension.
2941 * @param pSession The session.
2942 * @param pIrp Request packet.
2943 * @param pStack The request stack pointer.
2944 */
2945static NTSTATUS vgdrvNtDeviceControlSlow(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
2946 PIRP pIrp, PIO_STACK_LOCATION pStack)
2947{
2948 NTSTATUS rcNt;
2949 uint32_t cbOut = 0;
2950 int rc = 0;
2951 Log2(("vgdrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
2952 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
2953 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
2954 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
2955
2956#if 0 /*def RT_ARCH_AMD64*/
2957 /* Don't allow 32-bit processes to do any I/O controls. */
2958 if (!IoIs32bitProcess(pIrp))
2959#endif
2960 {
2961 /* Verify that it's a buffered CTL. */
2962 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
2963 {
2964 /* Verify that the sizes in the request header are correct. */
2965 PVBGLREQHDR pHdr = (PVBGLREQHDR)pIrp->AssociatedIrp.SystemBuffer;
2966 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
2967 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
2968 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
2969 {
2970 /* Zero extra output bytes to make sure we don't leak anything. */
2971 if (pHdr->cbIn < pHdr->cbOut)
2972 RtlZeroMemory((uint8_t *)pHdr + pHdr->cbIn, pHdr->cbOut - pHdr->cbIn);
2973
2974 /*
2975 * Do the job.
2976 */
2977 rc = VGDrvCommonIoCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr,
2978 RT_MAX(pHdr->cbIn, pHdr->cbOut));
2979 if (RT_SUCCESS(rc))
2980 {
2981 rcNt = STATUS_SUCCESS;
2982 cbOut = pHdr->cbOut;
2983 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
2984 {
2985 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
2986 LogRel(("vgdrvNtDeviceControlSlow: too much output! %#x > %#x; uCmd=%#x!\n",
2987 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
2988 }
2989
2990 /* If IDC successful disconnect request, we must set the context pointer to NULL. */
2991 if ( pStack->Parameters.DeviceIoControl.IoControlCode == VBGL_IOCTL_IDC_DISCONNECT
2992 && RT_SUCCESS(pHdr->rc))
2993 pStack->FileObject->FsContext = NULL;
2994 }
2995 else if (rc == VERR_NOT_SUPPORTED)
2996 rcNt = STATUS_NOT_SUPPORTED;
2997 else
2998 rcNt = STATUS_INVALID_PARAMETER;
2999 Log2(("vgdrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
3000 }
3001 else
3002 {
3003 Log(("vgdrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
3004 pStack->Parameters.DeviceIoControl.IoControlCode,
3005 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
3006 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
3007 pStack->Parameters.DeviceIoControl.InputBufferLength,
3008 pStack->Parameters.DeviceIoControl.OutputBufferLength));
3009 rcNt = STATUS_INVALID_PARAMETER;
3010 }
3011 }
3012 else
3013 {
3014 Log(("vgdrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
3015 pStack->Parameters.DeviceIoControl.IoControlCode));
3016 rcNt = STATUS_NOT_SUPPORTED;
3017 }
3018 }
3019#if 0 /*def RT_ARCH_AMD64*/
3020 else
3021 {
3022 Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
3023 rcNt = STATUS_NOT_SUPPORTED;
3024 }
3025#endif
3026
3027 return vgdrvNtCompleteRequestEx(rcNt, cbOut, pIrp);
3028}
3029
3030
3031/**
3032 * Internal Device I/O Control entry point (for IDC).
3033 *
3034 * @param pDevObj Device object.
3035 * @param pIrp Request packet.
3036 */
3037static NTSTATUS NTAPI vgdrvNtInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
3038{
3039 /* Currently no special code here. */
3040 return vgdrvNtDeviceControl(pDevObj, pIrp);
3041}
3042
3043
3044/**
3045 * IRP_MJ_SHUTDOWN handler.
3046 *
3047 * @returns NT status code
3048 * @param pDevObj Device object.
3049 * @param pIrp IRP.
3050 */
3051static NTSTATUS NTAPI vgdrvNtShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
3052{
3053 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
3054 LogFlowFuncEnter();
3055
3056 VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
3057 if (pReq)
3058 {
3059 pReq->header.requestType = VMMDevReq_SetPowerStatus;
3060 pReq->powerState = VMMDevPowerState_PowerOff;
3061
3062 int rc = VbglR0GRPerform(&pReq->header);
3063 if (RT_FAILURE(rc))
3064 LogFunc(("Error performing request to VMMDev, rc=%Rrc\n", rc));
3065 }
3066
3067 /* just in case, since we shouldn't normally get here. */
3068 pIrp->IoStatus.Information = 0;
3069 pIrp->IoStatus.Status = STATUS_SUCCESS;
3070 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
3071 return STATUS_SUCCESS;
3072}
3073
3074
3075/**
3076 * Stub function for functions we don't implemented.
3077 *
3078 * @returns STATUS_NOT_SUPPORTED
3079 * @param pDevObj Device object.
3080 * @param pIrp IRP.
3081 */
3082static NTSTATUS vgdrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
3083{
3084 RT_NOREF1(pDevObj);
3085 LogFlowFuncEnter();
3086
3087 pIrp->IoStatus.Information = 0;
3088 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
3089 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
3090
3091 return STATUS_NOT_SUPPORTED;
3092}
3093
3094
3095/**
3096 * Bug check callback (KBUGCHECK_CALLBACK_ROUTINE).
3097 *
3098 * This adds a log entry on the host, in case Hyper-V isn't active or the guest
3099 * is too old for reporting it itself via the crash MSRs.
3100 *
3101 * @param pvBuffer Not used.
3102 * @param cbBuffer Not used.
3103 */
3104static VOID NTAPI vgdrvNtBugCheckCallback(PVOID pvBuffer, ULONG cbBuffer)
3105{
3106 if (g_pauKiBugCheckData)
3107 {
3108 RTLogBackdoorPrintf("VBoxGuest: BugCheck! P0=%#zx P1=%#zx P2=%#zx P3=%#zx P4=%#zx\n", g_pauKiBugCheckData[0],
3109 g_pauKiBugCheckData[1], g_pauKiBugCheckData[2], g_pauKiBugCheckData[3], g_pauKiBugCheckData[4]);
3110
3111 VMMDevReqNtBugCheck *pReq = NULL;
3112 int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_NtBugCheck);
3113 if (RT_SUCCESS(rc))
3114 {
3115 pReq->uBugCheck = g_pauKiBugCheckData[0];
3116 pReq->auParameters[0] = g_pauKiBugCheckData[1];
3117 pReq->auParameters[1] = g_pauKiBugCheckData[2];
3118 pReq->auParameters[2] = g_pauKiBugCheckData[3];
3119 pReq->auParameters[3] = g_pauKiBugCheckData[4];
3120 VbglR0GRPerform(&pReq->header);
3121 VbglR0GRFree(&pReq->header);
3122 }
3123 }
3124 else
3125 {
3126 RTLogBackdoorPrintf("VBoxGuest: BugCheck!\n");
3127
3128 VMMDevRequestHeader *pReqHdr = NULL;
3129 int rc = VbglR0GRAlloc(&pReqHdr, sizeof(*pReqHdr), VMMDevReq_NtBugCheck);
3130 if (RT_SUCCESS(rc))
3131 {
3132 VbglR0GRPerform(pReqHdr);
3133 VbglR0GRFree(pReqHdr);
3134 }
3135 }
3136
3137 RT_NOREF(pvBuffer, cbBuffer);
3138}
3139
3140
3141/**
3142 * Sets the mouse notification callback.
3143 *
3144 * @returns VBox status code.
3145 * @param pDevExt Pointer to the device extension.
3146 * @param pNotify Pointer to the mouse notify struct.
3147 */
3148int VGDrvNativeSetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, PVBGLIOCSETMOUSENOTIFYCALLBACK pNotify)
3149{
3150 PVBOXGUESTDEVEXTWIN pDevExtWin = (PVBOXGUESTDEVEXTWIN)pDevExt;
3151 /* we need a lock here to avoid concurrency with the set event functionality */
3152 KIRQL OldIrql;
3153 KeAcquireSpinLock(&pDevExtWin->MouseEventAccessSpinLock, &OldIrql);
3154 pDevExtWin->Core.pfnMouseNotifyCallback = pNotify->u.In.pfnNotify;
3155 pDevExtWin->Core.pvMouseNotifyCallbackArg = pNotify->u.In.pvUser;
3156 KeReleaseSpinLock(&pDevExtWin->MouseEventAccessSpinLock, OldIrql);
3157 return VINF_SUCCESS;
3158}
3159
3160
3161/**
3162 * DPC handler.
3163 *
3164 * @param pDPC DPC descriptor.
3165 * @param pDevObj Device object.
3166 * @param pIrp Interrupt request packet.
3167 * @param pContext Context specific pointer.
3168 */
3169static void NTAPI vgdrvNtDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext)
3170{
3171 RT_NOREF3(pDPC, pIrp, pContext);
3172 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
3173 Log3Func(("pDevExt=0x%p\n", pDevExt));
3174
3175 /* Test & reset the counter. */
3176 if (ASMAtomicXchgU32(&pDevExt->Core.u32MousePosChangedSeq, 0))
3177 {
3178 /* we need a lock here to avoid concurrency with the set event ioctl handler thread,
3179 * i.e. to prevent the event from destroyed while we're using it */
3180 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
3181 KeAcquireSpinLockAtDpcLevel(&pDevExt->MouseEventAccessSpinLock);
3182
3183 if (pDevExt->Core.pfnMouseNotifyCallback)
3184 pDevExt->Core.pfnMouseNotifyCallback(pDevExt->Core.pvMouseNotifyCallbackArg);
3185
3186 KeReleaseSpinLockFromDpcLevel(&pDevExt->MouseEventAccessSpinLock);
3187 }
3188
3189 /* Process the wake-up list we were asked by the scheduling a DPC
3190 * in vgdrvNtIsrHandler(). */
3191 VGDrvCommonWaitDoWakeUps(&pDevExt->Core);
3192}
3193
3194
3195/**
3196 * ISR handler.
3197 *
3198 * @return BOOLEAN Indicates whether the IRQ came from us (TRUE) or not (FALSE).
3199 * @param pInterrupt Interrupt that was triggered.
3200 * @param pServiceContext Context specific pointer.
3201 */
3202static BOOLEAN NTAPI vgdrvNtIsrHandler(PKINTERRUPT pInterrupt, PVOID pServiceContext)
3203{
3204 RT_NOREF1(pInterrupt);
3205 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pServiceContext;
3206 if (pDevExt == NULL)
3207 return FALSE;
3208
3209 /*Log3Func(("pDevExt=0x%p, pVMMDevMemory=0x%p\n", pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL));*/
3210
3211 /* Enter the common ISR routine and do the actual work. */
3212 BOOLEAN fIRQTaken = VGDrvCommonISR(&pDevExt->Core);
3213
3214 /* If we need to wake up some events we do that in a DPC to make
3215 * sure we're called at the right IRQL. */
3216 if (fIRQTaken)
3217 {
3218 Log3Func(("IRQ was taken! pInterrupt=0x%p, pDevExt=0x%p\n", pInterrupt, pDevExt));
3219 if (ASMAtomicUoReadU32( &pDevExt->Core.u32MousePosChangedSeq)
3220 || !RTListIsEmpty(&pDevExt->Core.WakeUpList))
3221 {
3222 Log3Func(("Requesting DPC...\n"));
3223 IoRequestDpc(pDevExt->pDeviceObject, NULL /*pIrp*/, NULL /*pvContext*/);
3224 }
3225 }
3226 return fIRQTaken;
3227}
3228
3229
3230void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
3231{
3232 NOREF(pDevExt);
3233 /* nothing to do here - i.e. since we can not KeSetEvent from ISR level,
3234 * we rely on the pDevExt->u32MousePosChangedSeq to be set to a non-zero value on a mouse event
3235 * and queue the DPC in our ISR routine in that case doing KeSetEvent from the DPC routine */
3236}
3237
3238
3239/**
3240 * Hook for handling OS specfic options from the host.
3241 *
3242 * @returns true if handled, false if not.
3243 * @param pDevExt The device extension.
3244 * @param pszName The option name.
3245 * @param pszValue The option value.
3246 */
3247bool VGDrvNativeProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue)
3248{
3249 RT_NOREF(pDevExt); RT_NOREF(pszName); RT_NOREF(pszValue);
3250 return false;
3251}
3252
3253
3254/**
3255 * Implements RTL_QUERY_REGISTRY_ROUTINE for enumerating our registry key.
3256 */
3257static NTSTATUS NTAPI vgdrvNtRegistryEnumCallback(PWSTR pwszValueName, ULONG uValueType,
3258 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
3259{
3260 Log4(("vgdrvNtRegistryEnumCallback: pwszValueName=%ls uValueType=%#x Value=%.*Rhxs\n", pwszValueName, uValueType, cbValue, pvValue));
3261
3262 /*
3263 * Filter out general service config values.
3264 */
3265 if ( RTUtf16ICmpAscii(pwszValueName, "Type") == 0
3266 || RTUtf16ICmpAscii(pwszValueName, "Start") == 0
3267 || RTUtf16ICmpAscii(pwszValueName, "ErrorControl") == 0
3268 || RTUtf16ICmpAscii(pwszValueName, "Tag") == 0
3269 || RTUtf16ICmpAscii(pwszValueName, "ImagePath") == 0
3270 || RTUtf16ICmpAscii(pwszValueName, "DisplayName") == 0
3271 || RTUtf16ICmpAscii(pwszValueName, "Group") == 0
3272 || RTUtf16ICmpAscii(pwszValueName, "DependOnGroup") == 0
3273 || RTUtf16ICmpAscii(pwszValueName, "DependOnService") == 0
3274 )
3275 {
3276 return STATUS_SUCCESS;
3277 }
3278
3279 /*
3280 * Convert the value name.
3281 */
3282 size_t cch = RTUtf16CalcUtf8Len(pwszValueName);
3283 if (cch < 64 && cch > 0)
3284 {
3285 char szValueName[72];
3286 char *pszTmp = szValueName;
3287 int rc = RTUtf16ToUtf8Ex(pwszValueName, RTSTR_MAX, &pszTmp, sizeof(szValueName), NULL);
3288 if (RT_SUCCESS(rc))
3289 {
3290 /*
3291 * Convert the value.
3292 */
3293 char szValue[72];
3294 char *pszFree = NULL;
3295 char *pszValue = NULL;
3296 szValue[0] = '\0';
3297 switch (uValueType)
3298 {
3299 case REG_SZ:
3300 case REG_EXPAND_SZ:
3301 rc = RTUtf16CalcUtf8LenEx((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &cch);
3302 if (RT_SUCCESS(rc) && cch < _1K)
3303 {
3304 if (cch < sizeof(szValue))
3305 {
3306 pszValue = szValue;
3307 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &pszValue, sizeof(szValue), NULL);
3308 }
3309 else
3310 {
3311 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pvValue, cbValue / sizeof(RTUTF16), &pszValue, sizeof(szValue), NULL);
3312 if (RT_SUCCESS(rc))
3313 pszFree = pszValue;
3314 }
3315 if (RT_FAILURE(rc))
3316 {
3317 LogRel(("VBoxGuest: Failed to convert registry value '%ls' string data to UTF-8: %Rrc\n",
3318 pwszValueName, rc));
3319 pszValue = NULL;
3320 }
3321 }
3322 else if (RT_SUCCESS(rc))
3323 LogRel(("VBoxGuest: Registry value '%ls' has a too long value: %#x (uvalueType=%#x)\n",
3324 pwszValueName, cbValue, uValueType));
3325 else
3326 LogRel(("VBoxGuest: Registry value '%ls' has an invalid string value (cbValue=%#x, uvalueType=%#x)\n",
3327 pwszValueName, cbValue, uValueType));
3328 break;
3329
3330 case REG_DWORD:
3331 if (cbValue == sizeof(uint32_t))
3332 {
3333 RTStrFormatU32(szValue, sizeof(szValue), *(uint32_t const *)pvValue, 10, 0, 0, 0);
3334 pszValue = szValue;
3335 }
3336 else
3337 LogRel(("VBoxGuest: Registry value '%ls' has wrong length for REG_DWORD: %#x\n", pwszValueName, cbValue));
3338 break;
3339
3340 case REG_QWORD:
3341 if (cbValue == sizeof(uint64_t))
3342 {
3343 RTStrFormatU32(szValue, sizeof(szValue), *(uint32_t const *)pvValue, 10, 0, 0, 0);
3344 pszValue = szValue;
3345 }
3346 else
3347 LogRel(("VBoxGuest: Registry value '%ls' has wrong length for REG_DWORD: %#x\n", pwszValueName, cbValue));
3348 break;
3349
3350 default:
3351 LogRel(("VBoxGuest: Ignoring registry value '%ls': Unsupported type %#x\n", pwszValueName, uValueType));
3352 break;
3353 }
3354 if (pszValue)
3355 {
3356 /*
3357 * Process it.
3358 */
3359 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
3360 VGDrvCommonProcessOption(pDevExt, szValueName, pszValue);
3361 if (pszFree)
3362 RTStrFree(pszFree);
3363 }
3364 }
3365 }
3366 else if (cch > 0)
3367 LogRel(("VBoxGuest: Ignoring registery value '%ls': name too long\n", pwszValueName));
3368 else
3369 LogRel(("VBoxGuest: Ignoring registery value with bad name\n", pwszValueName));
3370 NOREF(pvEntryCtx);
3371 return STATUS_SUCCESS;
3372}
3373
3374
3375/**
3376 * Reads configuration from the registry and guest properties.
3377 *
3378 * We ignore failures and instead preserve existing configuration values.
3379 *
3380 * Thie routine will block.
3381 *
3382 * @param pDevExt The device extension.
3383 */
3384static void vgdrvNtReadConfiguration(PVBOXGUESTDEVEXTWIN pDevExt)
3385{
3386 /*
3387 * First the registry.
3388 *
3389 * Note! RTL_QUERY_REGISTRY_NOEXPAND is sensible (no environment) and also necessary to
3390 * avoid crash on NT 3.1 because RtlExpandEnvironmentStrings_U thinks its in ring-3
3391 * and tries to get the default heap from the PEB via the TEB. No TEB in ring-0.
3392 */
3393 RTL_QUERY_REGISTRY_TABLE aQuery[2];
3394 RT_ZERO(aQuery);
3395 aQuery[0].QueryRoutine = vgdrvNtRegistryEnumCallback;
3396 aQuery[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
3397 aQuery[0].Name = NULL;
3398 aQuery[0].EntryContext = NULL;
3399 aQuery[0].DefaultType = REG_NONE;
3400 NTSTATUS rcNt = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, L"VBoxGuest", &aQuery[0], pDevExt, NULL /*pwszzEnv*/);
3401 if (!NT_SUCCESS(rcNt))
3402 LogRel(("VBoxGuest: RtlQueryRegistryValues failed: %#x\n", rcNt));
3403
3404 /*
3405 * Read configuration from the host.
3406 */
3407 VGDrvCommonProcessOptionsFromHost(&pDevExt->Core);
3408}
3409
3410#ifdef VBOX_STRICT
3411
3412/**
3413 * A quick implementation of AtomicTestAndClear for uint32_t and multiple bits.
3414 */
3415static uint32_t vgdrvNtAtomicBitsTestAndClear(void *pu32Bits, uint32_t u32Mask)
3416{
3417 AssertPtrReturn(pu32Bits, 0);
3418 LogFlowFunc(("*pu32Bits=%#x, u32Mask=%#x\n", *(uint32_t *)pu32Bits, u32Mask));
3419 uint32_t u32Result = 0;
3420 uint32_t u32WorkingMask = u32Mask;
3421 int iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
3422
3423 while (iBitOffset > 0)
3424 {
3425 bool fSet = ASMAtomicBitTestAndClear(pu32Bits, iBitOffset - 1);
3426 if (fSet)
3427 u32Result |= 1 << (iBitOffset - 1);
3428 u32WorkingMask &= ~(1 << (iBitOffset - 1));
3429 iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
3430 }
3431 LogFlowFunc(("Returning %#x\n", u32Result));
3432 return u32Result;
3433}
3434
3435
3436static void vgdrvNtTestAtomicTestAndClearBitsU32(uint32_t u32Mask, uint32_t u32Bits, uint32_t u32Exp)
3437{
3438 ULONG u32Bits2 = u32Bits;
3439 uint32_t u32Result = vgdrvNtAtomicBitsTestAndClear(&u32Bits2, u32Mask);
3440 if ( u32Result != u32Exp
3441 || (u32Bits2 & u32Mask)
3442 || (u32Bits2 & u32Result)
3443 || ((u32Bits2 | u32Result) != u32Bits)
3444 )
3445 AssertLogRelMsgFailed(("TEST FAILED: u32Mask=%#x, u32Bits (before)=%#x, u32Bits (after)=%#x, u32Result=%#x, u32Exp=%#x\n",
3446 u32Mask, u32Bits, u32Bits2, u32Result));
3447}
3448
3449
3450static void vgdrvNtDoTests(void)
3451{
3452 vgdrvNtTestAtomicTestAndClearBitsU32(0x00, 0x23, 0);
3453 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0, 0);
3454 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x22, 0);
3455 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x23, 0x1);
3456 vgdrvNtTestAtomicTestAndClearBitsU32(0x11, 0x32, 0x10);
3457 vgdrvNtTestAtomicTestAndClearBitsU32(0x22, 0x23, 0x22);
3458}
3459
3460#endif /* VBOX_STRICT */
3461
3462#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
3463
3464/*
3465 * DPC latency checker.
3466 */
3467
3468/**
3469 * One DPC latency sample.
3470 */
3471typedef struct DPCSAMPLE
3472{
3473 LARGE_INTEGER PerfDelta;
3474 LARGE_INTEGER PerfCounter;
3475 LARGE_INTEGER PerfFrequency;
3476 uint64_t u64TSC;
3477} DPCSAMPLE;
3478AssertCompileSize(DPCSAMPLE, 4*8);
3479
3480/**
3481 * The DPC latency measurement workset.
3482 */
3483typedef struct DPCDATA
3484{
3485 KDPC Dpc;
3486 KTIMER Timer;
3487 KSPIN_LOCK SpinLock;
3488
3489 ULONG ulTimerRes;
3490
3491 bool volatile fFinished;
3492
3493 /** The timer interval (relative). */
3494 LARGE_INTEGER DueTime;
3495
3496 LARGE_INTEGER PerfCounterPrev;
3497
3498 /** Align the sample array on a 64 byte boundrary just for the off chance
3499 * that we'll get cache line aligned memory backing this structure. */
3500 uint32_t auPadding[ARCH_BITS == 32 ? 5 : 7];
3501
3502 int cSamples;
3503 DPCSAMPLE aSamples[8192];
3504} DPCDATA;
3505
3506AssertCompileMemberAlignment(DPCDATA, aSamples, 64);
3507
3508/**
3509 * DPC callback routine for the DPC latency measurement code.
3510 *
3511 * @param pDpc The DPC, not used.
3512 * @param pvDeferredContext Pointer to the DPCDATA.
3513 * @param SystemArgument1 System use, ignored.
3514 * @param SystemArgument2 System use, ignored.
3515 */
3516static VOID vgdrvNtDpcLatencyCallback(PKDPC pDpc, PVOID pvDeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
3517{
3518 DPCDATA *pData = (DPCDATA *)pvDeferredContext;
3519 RT_NOREF(pDpc, SystemArgument1, SystemArgument2);
3520
3521 KeAcquireSpinLockAtDpcLevel(&pData->SpinLock);
3522
3523 if (pData->cSamples >= RT_ELEMENTS(pData->aSamples))
3524 pData->fFinished = true;
3525 else
3526 {
3527 DPCSAMPLE *pSample = &pData->aSamples[pData->cSamples++];
3528
3529 pSample->u64TSC = ASMReadTSC();
3530 pSample->PerfCounter = KeQueryPerformanceCounter(&pSample->PerfFrequency);
3531 pSample->PerfDelta.QuadPart = pSample->PerfCounter.QuadPart - pData->PerfCounterPrev.QuadPart;
3532
3533 pData->PerfCounterPrev.QuadPart = pSample->PerfCounter.QuadPart;
3534
3535 KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
3536 }
3537
3538 KeReleaseSpinLockFromDpcLevel(&pData->SpinLock);
3539}
3540
3541
3542/**
3543 * Handles the DPC latency checker request.
3544 *
3545 * @returns VBox status code.
3546 */
3547int VGDrvNtIOCtl_DpcLatencyChecker(void)
3548{
3549 /*
3550 * Allocate a block of non paged memory for samples and related data.
3551 */
3552 DPCDATA *pData = (DPCDATA *)RTMemAlloc(sizeof(DPCDATA));
3553 if (!pData)
3554 {
3555 RTLogBackdoorPrintf("VBoxGuest: DPC: DPCDATA allocation failed.\n");
3556 return VERR_NO_MEMORY;
3557 }
3558
3559 /*
3560 * Initialize the data.
3561 */
3562 KeInitializeDpc(&pData->Dpc, vgdrvNtDpcLatencyCallback, pData);
3563 KeInitializeTimer(&pData->Timer);
3564 KeInitializeSpinLock(&pData->SpinLock);
3565
3566 pData->fFinished = false;
3567 pData->cSamples = 0;
3568 pData->PerfCounterPrev.QuadPart = 0;
3569
3570 pData->ulTimerRes = ExSetTimerResolution(1000 * 10, 1);
3571 pData->DueTime.QuadPart = -(int64_t)pData->ulTimerRes / 10;
3572
3573 /*
3574 * Start the DPC measurements and wait for a full set.
3575 */
3576 KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
3577
3578 while (!pData->fFinished)
3579 {
3580 LARGE_INTEGER Interval;
3581 Interval.QuadPart = -100 * 1000 * 10;
3582 KeDelayExecutionThread(KernelMode, TRUE, &Interval);
3583 }
3584
3585 ExSetTimerResolution(0, 0);
3586
3587 /*
3588 * Log everything to the host.
3589 */
3590 RTLogBackdoorPrintf("DPC: ulTimerRes = %d\n", pData->ulTimerRes);
3591 for (int i = 0; i < pData->cSamples; i++)
3592 {
3593 DPCSAMPLE *pSample = &pData->aSamples[i];
3594
3595 RTLogBackdoorPrintf("[%d] pd %lld pc %lld pf %lld t %lld\n",
3596 i,
3597 pSample->PerfDelta.QuadPart,
3598 pSample->PerfCounter.QuadPart,
3599 pSample->PerfFrequency.QuadPart,
3600 pSample->u64TSC);
3601 }
3602
3603 RTMemFree(pData);
3604 return VINF_SUCCESS;
3605}
3606
3607#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
3608
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