VirtualBox

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

Last change on this file since 91546 was 91546, checked in by vboxsync, 3 years ago

Additions, VMMDev: More Windows 11 detection.

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