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