VirtualBox

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

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

scm --update-copyright-year

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