VirtualBox

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

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

VMMDev,VBoxGuest: Classify who is calling the host (part 1). bugref:9105

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