[14462] | 1 | /* $Id: VBoxGuest.cpp 100363 2023-07-04 09:34:19Z vboxsync $ */
|
---|
[3657] | 2 | /** @file
|
---|
[21095] | 3 | * VBoxGuest - Guest Additions Driver, Common Code.
|
---|
[3657] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2007-2023 Oracle and/or its affiliates.
|
---|
[3657] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[41722] | 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 | *
|
---|
[41722] | 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
|
---|
[41722] | 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
|
---|
[3657] | 35 | */
|
---|
| 36 |
|
---|
[58053] | 37 | /** @page pg_vbdrv VBoxGuest
|
---|
| 38 | *
|
---|
| 39 | * VBoxGuest is the device driver for VMMDev.
|
---|
| 40 | *
|
---|
| 41 | * The device driver is shipped as part of the guest additions. It has roots in
|
---|
| 42 | * the host VMM support driver (usually known as VBoxDrv), so fixes in platform
|
---|
| 43 | * specific code may apply to both drivers.
|
---|
| 44 | *
|
---|
| 45 | * The common code lives in VBoxGuest.cpp and is compiled both as C++ and C.
|
---|
| 46 | * The VBoxGuest.cpp source file shall not contain platform specific code,
|
---|
| 47 | * though it must occationally do a few \#ifdef RT_OS_XXX tests to cater for
|
---|
| 48 | * platform differences. Though, in those cases, it is common that more than
|
---|
| 49 | * one platform needs special handling.
|
---|
| 50 | *
|
---|
| 51 | * On most platforms the device driver should create two device nodes, one for
|
---|
| 52 | * full (unrestricted) access to the feature set, and one which only provides a
|
---|
| 53 | * restrict set of functions. These are generally referred to as 'vboxguest'
|
---|
| 54 | * and 'vboxuser' respectively. Currently, this two device approach is only
|
---|
| 55 | * implemented on Linux!
|
---|
| 56 | *
|
---|
| 57 | */
|
---|
[3657] | 58 |
|
---|
[58053] | 59 |
|
---|
[57358] | 60 | /*********************************************************************************************************************************
|
---|
| 61 | * Header Files *
|
---|
| 62 | *********************************************************************************************************************************/
|
---|
[3657] | 63 | #define LOG_GROUP LOG_GROUP_DEFAULT
|
---|
| 64 | #include "VBoxGuestInternal.h"
|
---|
[21219] | 65 | #include <VBox/VMMDev.h> /* for VMMDEV_RAM_SIZE */
|
---|
[76419] | 66 | #include <VBox/err.h>
|
---|
[3657] | 67 | #include <VBox/log.h>
|
---|
[70085] | 68 | #include <VBox/HostServices/GuestPropertySvc.h>
|
---|
[70040] | 69 | #include <iprt/ctype.h>
|
---|
[3657] | 70 | #include <iprt/mem.h>
|
---|
| 71 | #include <iprt/time.h>
|
---|
| 72 | #include <iprt/memobj.h>
|
---|
| 73 | #include <iprt/asm.h>
|
---|
[100267] | 74 | #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
|
---|
| 75 | # include <iprt/asm-amd64-x86.h>
|
---|
| 76 | #endif
|
---|
[3657] | 77 | #include <iprt/string.h>
|
---|
| 78 | #include <iprt/process.h>
|
---|
| 79 | #include <iprt/assert.h>
|
---|
| 80 | #include <iprt/param.h>
|
---|
[52789] | 81 | #include <iprt/timer.h>
|
---|
[11820] | 82 | #ifdef VBOX_WITH_HGCM
|
---|
[3657] | 83 | # include <iprt/thread.h>
|
---|
[6032] | 84 | #endif
|
---|
[29043] | 85 | #include "version-generated.h"
|
---|
| 86 | #if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
|
---|
| 87 | # include "revision-generated.h"
|
---|
| 88 | #endif
|
---|
[45459] | 89 | #if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
|
---|
[33054] | 90 | # include <iprt/rand.h>
|
---|
| 91 | #endif
|
---|
[3657] | 92 |
|
---|
| 93 |
|
---|
[57358] | 94 | /*********************************************************************************************************************************
|
---|
| 95 | * Defined Constants And Macros *
|
---|
| 96 | *********************************************************************************************************************************/
|
---|
[45779] | 97 | #define VBOXGUEST_ACQUIRE_STYLE_EVENTS (VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
|
---|
[45778] | 98 |
|
---|
[45760] | 99 |
|
---|
[57358] | 100 | /*********************************************************************************************************************************
|
---|
| 101 | * Internal Functions *
|
---|
| 102 | *********************************************************************************************************************************/
|
---|
[54593] | 103 | #ifdef VBOX_WITH_HGCM
|
---|
[58053] | 104 | static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdrNonVolatile, void *pvUser, uint32_t u32User);
|
---|
[54593] | 105 | #endif
|
---|
[58053] | 106 | static int vgdrvIoCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
|
---|
| 107 | static void vgdrvBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker);
|
---|
| 108 | static uint32_t vgdrvGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
|
---|
| 109 | static int vgdrvResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt, uint32_t fFixedEvents);
|
---|
| 110 | static int vgdrvResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt);
|
---|
| 111 | static int vgdrvResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt);
|
---|
| 112 | static int vgdrvSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
| 113 | uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination);
|
---|
| 114 | static int vgdrvSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
| 115 | uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination);
|
---|
| 116 | static int vgdrvSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
[68550] | 117 | uint32_t fOrMask, uint32_t fNoMask,
|
---|
| 118 | uint32_t *pfSessionCaps, uint32_t *pfGlobalCaps, bool fSessionTermination);
|
---|
| 119 | static int vgdrvAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
| 120 | uint32_t fOrMask, uint32_t fNotMask, uint32_t fFlags, bool fSessionTermination);
|
---|
[58053] | 121 | static int vgdrvDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents);
|
---|
[50523] | 122 |
|
---|
[50539] | 123 |
|
---|
[57358] | 124 | /*********************************************************************************************************************************
|
---|
| 125 | * Global Variables *
|
---|
| 126 | *********************************************************************************************************************************/
|
---|
[73097] | 127 | static const uint32_t g_cbChangeMemBalloonReq = RT_UOFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]);
|
---|
[3657] | 128 |
|
---|
[45459] | 129 | #if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
|
---|
[33054] | 130 | /**
|
---|
| 131 | * Drag in the rest of IRPT since we share it with the
|
---|
| 132 | * rest of the kernel modules on Solaris.
|
---|
| 133 | */
|
---|
[85321] | 134 | struct CLANG11WEIRDNESS { PFNRT pfn; } g_apfnVBoxGuestIPRTDeps[] =
|
---|
[33054] | 135 | {
|
---|
| 136 | /* VirtioNet */
|
---|
[85321] | 137 | { (PFNRT)RTRandBytes },
|
---|
[42366] | 138 | /* RTSemMutex* */
|
---|
[85321] | 139 | { (PFNRT)RTSemMutexCreate },
|
---|
| 140 | { (PFNRT)RTSemMutexDestroy },
|
---|
| 141 | { (PFNRT)RTSemMutexRequest },
|
---|
| 142 | { (PFNRT)RTSemMutexRequestNoResume },
|
---|
| 143 | { (PFNRT)RTSemMutexRequestDebug },
|
---|
| 144 | { (PFNRT)RTSemMutexRequestNoResumeDebug },
|
---|
| 145 | { (PFNRT)RTSemMutexRelease },
|
---|
| 146 | { (PFNRT)RTSemMutexIsOwned },
|
---|
| 147 | { NULL }
|
---|
[33054] | 148 | };
|
---|
[45459] | 149 | #endif /* RT_OS_DARWIN || RT_OS_SOLARIS */
|
---|
[27106] | 150 |
|
---|
| 151 |
|
---|
[3657] | 152 | /**
|
---|
| 153 | * Reserves memory in which the VMM can relocate any guest mappings
|
---|
| 154 | * that are floating around.
|
---|
[6032] | 155 | *
|
---|
| 156 | * This operation is a little bit tricky since the VMM might not accept
|
---|
[3657] | 157 | * just any address because of address clashes between the three contexts
|
---|
| 158 | * it operates in, so use a small stack to perform this operation.
|
---|
[6032] | 159 | *
|
---|
[3657] | 160 | * @returns VBox status code (ignored).
|
---|
| 161 | * @param pDevExt The device extension.
|
---|
| 162 | */
|
---|
[58053] | 163 | static int vgdrvInitFixateGuestMappings(PVBOXGUESTDEVEXT pDevExt)
|
---|
[3657] | 164 | {
|
---|
[21498] | 165 | /*
|
---|
| 166 | * Query the required space.
|
---|
| 167 | */
|
---|
| 168 | VMMDevReqHypervisorInfo *pReq;
|
---|
[68654] | 169 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevReqHypervisorInfo), VMMDevReq_GetHypervisorInfo);
|
---|
[21498] | 170 | if (RT_FAILURE(rc))
|
---|
| 171 | return rc;
|
---|
| 172 | pReq->hypervisorStart = 0;
|
---|
| 173 | pReq->hypervisorSize = 0;
|
---|
[68654] | 174 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[21498] | 175 | if (RT_FAILURE(rc)) /* this shouldn't happen! */
|
---|
| 176 | {
|
---|
[68654] | 177 | VbglR0GRFree(&pReq->header);
|
---|
[21498] | 178 | return rc;
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | /*
|
---|
| 182 | * The VMM will report back if there is nothing it wants to map, like for
|
---|
[32290] | 183 | * instance in VT-x and AMD-V mode.
|
---|
[21498] | 184 | */
|
---|
| 185 | if (pReq->hypervisorSize == 0)
|
---|
[58053] | 186 | Log(("vgdrvInitFixateGuestMappings: nothing to do\n"));
|
---|
[21498] | 187 | else
|
---|
| 188 | {
|
---|
| 189 | /*
|
---|
| 190 | * We have to try several times since the host can be picky
|
---|
| 191 | * about certain addresses.
|
---|
| 192 | */
|
---|
| 193 | RTR0MEMOBJ hFictive = NIL_RTR0MEMOBJ;
|
---|
| 194 | uint32_t cbHypervisor = pReq->hypervisorSize;
|
---|
| 195 | RTR0MEMOBJ ahTries[5];
|
---|
| 196 | uint32_t iTry;
|
---|
[21632] | 197 | bool fBitched = false;
|
---|
[58053] | 198 | Log(("vgdrvInitFixateGuestMappings: cbHypervisor=%#x\n", cbHypervisor));
|
---|
[21498] | 199 | for (iTry = 0; iTry < RT_ELEMENTS(ahTries); iTry++)
|
---|
| 200 | {
|
---|
| 201 | /*
|
---|
| 202 | * Reserve space, or if that isn't supported, create a object for
|
---|
| 203 | * some fictive physical memory and map that in to kernel space.
|
---|
| 204 | *
|
---|
| 205 | * To make the code a bit uglier, most systems cannot help with
|
---|
| 206 | * 4MB alignment, so we have to deal with that in addition to
|
---|
| 207 | * having two ways of getting the memory.
|
---|
| 208 | */
|
---|
| 209 | uint32_t uAlignment = _4M;
|
---|
| 210 | RTR0MEMOBJ hObj;
|
---|
| 211 | rc = RTR0MemObjReserveKernel(&hObj, (void *)-1, RT_ALIGN_32(cbHypervisor, _4M), uAlignment);
|
---|
| 212 | if (rc == VERR_NOT_SUPPORTED)
|
---|
| 213 | {
|
---|
| 214 | uAlignment = PAGE_SIZE;
|
---|
| 215 | rc = RTR0MemObjReserveKernel(&hObj, (void *)-1, RT_ALIGN_32(cbHypervisor, _4M) + _4M, uAlignment);
|
---|
| 216 | }
|
---|
[32290] | 217 | /*
|
---|
| 218 | * If both RTR0MemObjReserveKernel calls above failed because either not supported or
|
---|
| 219 | * not implemented at all at the current platform, try to map the memory object into the
|
---|
| 220 | * virtual kernel space.
|
---|
| 221 | */
|
---|
[32349] | 222 | if (rc == VERR_NOT_SUPPORTED)
|
---|
[21498] | 223 | {
|
---|
| 224 | if (hFictive == NIL_RTR0MEMOBJ)
|
---|
| 225 | {
|
---|
[28777] | 226 | rc = RTR0MemObjEnterPhys(&hObj, VBOXGUEST_HYPERVISOR_PHYSICAL_START, cbHypervisor + _4M, RTMEM_CACHE_POLICY_DONT_CARE);
|
---|
[21498] | 227 | if (RT_FAILURE(rc))
|
---|
| 228 | break;
|
---|
| 229 | hFictive = hObj;
|
---|
| 230 | }
|
---|
| 231 | uAlignment = _4M;
|
---|
| 232 | rc = RTR0MemObjMapKernel(&hObj, hFictive, (void *)-1, uAlignment, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
|
---|
| 233 | if (rc == VERR_NOT_SUPPORTED)
|
---|
| 234 | {
|
---|
| 235 | uAlignment = PAGE_SIZE;
|
---|
| 236 | rc = RTR0MemObjMapKernel(&hObj, hFictive, (void *)-1, uAlignment, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
|
---|
| 237 | }
|
---|
| 238 | }
|
---|
| 239 | if (RT_FAILURE(rc))
|
---|
| 240 | {
|
---|
| 241 | LogRel(("VBoxGuest: Failed to reserve memory for the hypervisor: rc=%Rrc (cbHypervisor=%#x uAlignment=%#x iTry=%u)\n",
|
---|
| 242 | rc, cbHypervisor, uAlignment, iTry));
|
---|
[21632] | 243 | fBitched = true;
|
---|
[21498] | 244 | break;
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | /*
|
---|
| 248 | * Try set it.
|
---|
| 249 | */
|
---|
| 250 | pReq->header.requestType = VMMDevReq_SetHypervisorInfo;
|
---|
| 251 | pReq->header.rc = VERR_INTERNAL_ERROR;
|
---|
| 252 | pReq->hypervisorSize = cbHypervisor;
|
---|
[51224] | 253 | pReq->hypervisorStart = (RTGCPTR32)(uintptr_t)RTR0MemObjAddress(hObj);
|
---|
[21498] | 254 | if ( uAlignment == PAGE_SIZE
|
---|
| 255 | && pReq->hypervisorStart & (_4M - 1))
|
---|
| 256 | pReq->hypervisorStart = RT_ALIGN_32(pReq->hypervisorStart, _4M);
|
---|
| 257 | AssertMsg(RT_ALIGN_32(pReq->hypervisorStart, _4M) == pReq->hypervisorStart, ("%#x\n", pReq->hypervisorStart));
|
---|
| 258 |
|
---|
[68654] | 259 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[21498] | 260 | if (RT_SUCCESS(rc))
|
---|
| 261 | {
|
---|
| 262 | pDevExt->hGuestMappings = hFictive != NIL_RTR0MEMOBJ ? hFictive : hObj;
|
---|
[26358] | 263 | Log(("VBoxGuest: %p LB %#x; uAlignment=%#x iTry=%u hGuestMappings=%p (%s)\n",
|
---|
[26504] | 264 | RTR0MemObjAddress(pDevExt->hGuestMappings),
|
---|
| 265 | RTR0MemObjSize(pDevExt->hGuestMappings),
|
---|
| 266 | uAlignment, iTry, pDevExt->hGuestMappings, hFictive != NIL_RTR0PTR ? "fictive" : "reservation"));
|
---|
[21498] | 267 | break;
|
---|
| 268 | }
|
---|
| 269 | ahTries[iTry] = hObj;
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | /*
|
---|
| 273 | * Cleanup failed attempts.
|
---|
| 274 | */
|
---|
| 275 | while (iTry-- > 0)
|
---|
| 276 | RTR0MemObjFree(ahTries[iTry], false /* fFreeMappings */);
|
---|
| 277 | if ( RT_FAILURE(rc)
|
---|
| 278 | && hFictive != NIL_RTR0PTR)
|
---|
| 279 | RTR0MemObjFree(hFictive, false /* fFreeMappings */);
|
---|
[21632] | 280 | if (RT_FAILURE(rc) && !fBitched)
|
---|
| 281 | LogRel(("VBoxGuest: Warning: failed to reserve %#d of memory for guest mappings.\n", cbHypervisor));
|
---|
[21498] | 282 | }
|
---|
[68654] | 283 | VbglR0GRFree(&pReq->header);
|
---|
[21498] | 284 |
|
---|
| 285 | /*
|
---|
| 286 | * We ignore failed attempts for now.
|
---|
| 287 | */
|
---|
[3657] | 288 | return VINF_SUCCESS;
|
---|
| 289 | }
|
---|
| 290 |
|
---|
| 291 |
|
---|
| 292 | /**
|
---|
[58053] | 293 | * Undo what vgdrvInitFixateGuestMappings did.
|
---|
[6032] | 294 | *
|
---|
[21498] | 295 | * @param pDevExt The device extension.
|
---|
| 296 | */
|
---|
[58053] | 297 | static void vgdrvTermUnfixGuestMappings(PVBOXGUESTDEVEXT pDevExt)
|
---|
[21498] | 298 | {
|
---|
| 299 | if (pDevExt->hGuestMappings != NIL_RTR0PTR)
|
---|
| 300 | {
|
---|
| 301 | /*
|
---|
| 302 | * Tell the host that we're going to free the memory we reserved for
|
---|
| 303 | * it, the free it up. (Leak the memory if anything goes wrong here.)
|
---|
| 304 | */
|
---|
| 305 | VMMDevReqHypervisorInfo *pReq;
|
---|
[68654] | 306 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevReqHypervisorInfo), VMMDevReq_SetHypervisorInfo);
|
---|
[21498] | 307 | if (RT_SUCCESS(rc))
|
---|
| 308 | {
|
---|
| 309 | pReq->hypervisorStart = 0;
|
---|
| 310 | pReq->hypervisorSize = 0;
|
---|
[68654] | 311 | rc = VbglR0GRPerform(&pReq->header);
|
---|
| 312 | VbglR0GRFree(&pReq->header);
|
---|
[21498] | 313 | }
|
---|
| 314 | if (RT_SUCCESS(rc))
|
---|
| 315 | {
|
---|
| 316 | rc = RTR0MemObjFree(pDevExt->hGuestMappings, true /* fFreeMappings */);
|
---|
| 317 | AssertRC(rc);
|
---|
| 318 | }
|
---|
| 319 | else
|
---|
[58053] | 320 | LogRel(("vgdrvTermUnfixGuestMappings: Failed to unfix the guest mappings! rc=%Rrc\n", rc));
|
---|
[21498] | 321 |
|
---|
| 322 | pDevExt->hGuestMappings = NIL_RTR0MEMOBJ;
|
---|
| 323 | }
|
---|
| 324 | }
|
---|
| 325 |
|
---|
| 326 |
|
---|
[54609] | 327 |
|
---|
| 328 | /**
|
---|
| 329 | * Report the guest information to the host.
|
---|
| 330 | *
|
---|
| 331 | * @returns IPRT status code.
|
---|
| 332 | * @param enmOSType The OS type to report.
|
---|
| 333 | */
|
---|
[58053] | 334 | static int vgdrvReportGuestInfo(VBOXOSTYPE enmOSType)
|
---|
[54609] | 335 | {
|
---|
| 336 | /*
|
---|
| 337 | * Allocate and fill in the two guest info reports.
|
---|
| 338 | */
|
---|
| 339 | VMMDevReportGuestInfo2 *pReqInfo2 = NULL;
|
---|
| 340 | VMMDevReportGuestInfo *pReqInfo1 = NULL;
|
---|
[68654] | 341 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReqInfo2, sizeof (VMMDevReportGuestInfo2), VMMDevReq_ReportGuestInfo2);
|
---|
| 342 | Log(("vgdrvReportGuestInfo: VbglR0GRAlloc VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc));
|
---|
[54609] | 343 | if (RT_SUCCESS(rc))
|
---|
| 344 | {
|
---|
| 345 | pReqInfo2->guestInfo.additionsMajor = VBOX_VERSION_MAJOR;
|
---|
| 346 | pReqInfo2->guestInfo.additionsMinor = VBOX_VERSION_MINOR;
|
---|
| 347 | pReqInfo2->guestInfo.additionsBuild = VBOX_VERSION_BUILD;
|
---|
| 348 | pReqInfo2->guestInfo.additionsRevision = VBOX_SVN_REV;
|
---|
[70873] | 349 | pReqInfo2->guestInfo.additionsFeatures = VBOXGSTINFO2_F_REQUESTOR_INFO;
|
---|
[54609] | 350 | RTStrCopy(pReqInfo2->guestInfo.szName, sizeof(pReqInfo2->guestInfo.szName), VBOX_VERSION_STRING);
|
---|
| 351 |
|
---|
[68654] | 352 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReqInfo1, sizeof (VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
|
---|
| 353 | Log(("vgdrvReportGuestInfo: VbglR0GRAlloc VMMDevReportGuestInfo completed with rc=%Rrc\n", rc));
|
---|
[54609] | 354 | if (RT_SUCCESS(rc))
|
---|
| 355 | {
|
---|
| 356 | pReqInfo1->guestInfo.interfaceVersion = VMMDEV_VERSION;
|
---|
| 357 | pReqInfo1->guestInfo.osType = enmOSType;
|
---|
| 358 |
|
---|
| 359 | /*
|
---|
| 360 | * There are two protocols here:
|
---|
| 361 | * 1. Info2 + Info1. Supported by >=3.2.51.
|
---|
| 362 | * 2. Info1 and optionally Info2. The old protocol.
|
---|
| 363 | *
|
---|
| 364 | * We try protocol 1 first. It will fail with VERR_NOT_SUPPORTED
|
---|
| 365 | * if not supported by the VMMDev (message ordering requirement).
|
---|
| 366 | */
|
---|
[68654] | 367 | rc = VbglR0GRPerform(&pReqInfo2->header);
|
---|
| 368 | Log(("vgdrvReportGuestInfo: VbglR0GRPerform VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc));
|
---|
[54609] | 369 | if (RT_SUCCESS(rc))
|
---|
| 370 | {
|
---|
[68654] | 371 | rc = VbglR0GRPerform(&pReqInfo1->header);
|
---|
| 372 | Log(("vgdrvReportGuestInfo: VbglR0GRPerform VMMDevReportGuestInfo completed with rc=%Rrc\n", rc));
|
---|
[54609] | 373 | }
|
---|
| 374 | else if ( rc == VERR_NOT_SUPPORTED
|
---|
| 375 | || rc == VERR_NOT_IMPLEMENTED)
|
---|
| 376 | {
|
---|
[68654] | 377 | rc = VbglR0GRPerform(&pReqInfo1->header);
|
---|
| 378 | Log(("vgdrvReportGuestInfo: VbglR0GRPerform VMMDevReportGuestInfo completed with rc=%Rrc\n", rc));
|
---|
[54609] | 379 | if (RT_SUCCESS(rc))
|
---|
| 380 | {
|
---|
[68654] | 381 | rc = VbglR0GRPerform(&pReqInfo2->header);
|
---|
| 382 | Log(("vgdrvReportGuestInfo: VbglR0GRPerform VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc));
|
---|
[54609] | 383 | if (rc == VERR_NOT_IMPLEMENTED)
|
---|
| 384 | rc = VINF_SUCCESS;
|
---|
| 385 | }
|
---|
| 386 | }
|
---|
[68654] | 387 | VbglR0GRFree(&pReqInfo1->header);
|
---|
[54609] | 388 | }
|
---|
[68654] | 389 | VbglR0GRFree(&pReqInfo2->header);
|
---|
[54609] | 390 | }
|
---|
| 391 |
|
---|
| 392 | return rc;
|
---|
| 393 | }
|
---|
| 394 |
|
---|
| 395 |
|
---|
| 396 | /**
|
---|
| 397 | * Report the guest driver status to the host.
|
---|
| 398 | *
|
---|
| 399 | * @returns IPRT status code.
|
---|
| 400 | * @param fActive Flag whether the driver is now active or not.
|
---|
| 401 | */
|
---|
[58053] | 402 | static int vgdrvReportDriverStatus(bool fActive)
|
---|
[54609] | 403 | {
|
---|
| 404 | /*
|
---|
| 405 | * Report guest status of the VBox driver to the host.
|
---|
| 406 | */
|
---|
| 407 | VMMDevReportGuestStatus *pReq2 = NULL;
|
---|
[68654] | 408 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq2, sizeof(*pReq2), VMMDevReq_ReportGuestStatus);
|
---|
| 409 | Log(("vgdrvReportDriverStatus: VbglR0GRAlloc VMMDevReportGuestStatus completed with rc=%Rrc\n", rc));
|
---|
[54609] | 410 | if (RT_SUCCESS(rc))
|
---|
| 411 | {
|
---|
| 412 | pReq2->guestStatus.facility = VBoxGuestFacilityType_VBoxGuestDriver;
|
---|
| 413 | pReq2->guestStatus.status = fActive ?
|
---|
| 414 | VBoxGuestFacilityStatus_Active
|
---|
| 415 | : VBoxGuestFacilityStatus_Inactive;
|
---|
| 416 | pReq2->guestStatus.flags = 0;
|
---|
[68654] | 417 | rc = VbglR0GRPerform(&pReq2->header);
|
---|
| 418 | Log(("vgdrvReportDriverStatus: VbglR0GRPerform VMMDevReportGuestStatus completed with fActive=%d, rc=%Rrc\n",
|
---|
[54609] | 419 | fActive ? 1 : 0, rc));
|
---|
| 420 | if (rc == VERR_NOT_IMPLEMENTED) /* Compatibility with older hosts. */
|
---|
| 421 | rc = VINF_SUCCESS;
|
---|
[68654] | 422 | VbglR0GRFree(&pReq2->header);
|
---|
[54609] | 423 | }
|
---|
| 424 |
|
---|
| 425 | return rc;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 |
|
---|
[54608] | 429 | /** @name Memory Ballooning
|
---|
| 430 | * @{
|
---|
| 431 | */
|
---|
| 432 |
|
---|
[21498] | 433 | /**
|
---|
[27023] | 434 | * Inflate the balloon by one chunk represented by an R0 memory object.
|
---|
| 435 | *
|
---|
[27967] | 436 | * The caller owns the balloon mutex.
|
---|
| 437 | *
|
---|
[27023] | 438 | * @returns IPRT status code.
|
---|
| 439 | * @param pMemObj Pointer to the R0 memory object.
|
---|
| 440 | * @param pReq The pre-allocated request for performing the VMMDev call.
|
---|
| 441 | */
|
---|
[58053] | 442 | static int vgdrvBalloonInflate(PRTR0MEMOBJ pMemObj, VMMDevChangeMemBalloon *pReq)
|
---|
[27023] | 443 | {
|
---|
| 444 | uint32_t iPage;
|
---|
| 445 | int rc;
|
---|
[3657] | 446 |
|
---|
[27023] | 447 | for (iPage = 0; iPage < VMMDEV_MEMORY_BALLOON_CHUNK_PAGES; iPage++)
|
---|
| 448 | {
|
---|
| 449 | RTHCPHYS phys = RTR0MemObjGetPagePhysAddr(*pMemObj, iPage);
|
---|
| 450 | pReq->aPhysPage[iPage] = phys;
|
---|
| 451 | }
|
---|
| 452 |
|
---|
| 453 | pReq->fInflate = true;
|
---|
[54608] | 454 | pReq->header.size = g_cbChangeMemBalloonReq;
|
---|
[27023] | 455 | pReq->cPages = VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;
|
---|
| 456 |
|
---|
[68654] | 457 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[27054] | 458 | if (RT_FAILURE(rc))
|
---|
[68654] | 459 | LogRel(("vgdrvBalloonInflate: VbglR0GRPerform failed. rc=%Rrc\n", rc));
|
---|
[27054] | 460 | return rc;
|
---|
[27023] | 461 | }
|
---|
| 462 |
|
---|
[27054] | 463 |
|
---|
[3657] | 464 | /**
|
---|
[27106] | 465 | * Deflate the balloon by one chunk - info the host and free the memory object.
|
---|
[27023] | 466 | *
|
---|
[27967] | 467 | * The caller owns the balloon mutex.
|
---|
| 468 | *
|
---|
[27023] | 469 | * @returns IPRT status code.
|
---|
| 470 | * @param pMemObj Pointer to the R0 memory object.
|
---|
| 471 | * The memory object will be freed afterwards.
|
---|
| 472 | * @param pReq The pre-allocated request for performing the VMMDev call.
|
---|
| 473 | */
|
---|
[58053] | 474 | static int vgdrvBalloonDeflate(PRTR0MEMOBJ pMemObj, VMMDevChangeMemBalloon *pReq)
|
---|
[27023] | 475 | {
|
---|
| 476 | uint32_t iPage;
|
---|
| 477 | int rc;
|
---|
| 478 |
|
---|
| 479 | for (iPage = 0; iPage < VMMDEV_MEMORY_BALLOON_CHUNK_PAGES; iPage++)
|
---|
| 480 | {
|
---|
| 481 | RTHCPHYS phys = RTR0MemObjGetPagePhysAddr(*pMemObj, iPage);
|
---|
| 482 | pReq->aPhysPage[iPage] = phys;
|
---|
| 483 | }
|
---|
| 484 |
|
---|
| 485 | pReq->fInflate = false;
|
---|
[54608] | 486 | pReq->header.size = g_cbChangeMemBalloonReq;
|
---|
[27023] | 487 | pReq->cPages = VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;
|
---|
| 488 |
|
---|
[68654] | 489 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[27023] | 490 | if (RT_FAILURE(rc))
|
---|
[27054] | 491 | {
|
---|
[68654] | 492 | LogRel(("vgdrvBalloonDeflate: VbglR0GRPerform failed. rc=%Rrc\n", rc));
|
---|
[27023] | 493 | return rc;
|
---|
[27054] | 494 | }
|
---|
[27023] | 495 |
|
---|
| 496 | rc = RTR0MemObjFree(*pMemObj, true);
|
---|
| 497 | if (RT_FAILURE(rc))
|
---|
[27106] | 498 | {
|
---|
[58053] | 499 | LogRel(("vgdrvBalloonDeflate: RTR0MemObjFree(%p,true) -> %Rrc; this is *BAD*!\n", *pMemObj, rc));
|
---|
[27023] | 500 | return rc;
|
---|
[27106] | 501 | }
|
---|
[27023] | 502 |
|
---|
| 503 | *pMemObj = NIL_RTR0MEMOBJ;
|
---|
| 504 | return VINF_SUCCESS;
|
---|
| 505 | }
|
---|
| 506 |
|
---|
| 507 |
|
---|
| 508 | /**
|
---|
[26999] | 509 | * Inflate/deflate the memory balloon and notify the host.
|
---|
[26934] | 510 | *
|
---|
[58053] | 511 | * This is a worker used by vgdrvIoCtl_CheckMemoryBalloon - it takes the mutex.
|
---|
[27967] | 512 | *
|
---|
[26934] | 513 | * @returns VBox status code.
|
---|
[27106] | 514 | * @param pDevExt The device extension.
|
---|
[27023] | 515 | * @param cBalloonChunks The new size of the balloon in chunks of 1MB.
|
---|
[27967] | 516 | * @param pfHandleInR3 Where to return the handle-in-ring3 indicator
|
---|
| 517 | * (VINF_SUCCESS if set).
|
---|
[26934] | 518 | */
|
---|
[68550] | 519 | static int vgdrvSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt, uint32_t cBalloonChunks, bool *pfHandleInR3)
|
---|
[26934] | 520 | {
|
---|
| 521 | int rc = VINF_SUCCESS;
|
---|
| 522 |
|
---|
[26999] | 523 | if (pDevExt->MemBalloon.fUseKernelAPI)
|
---|
[26934] | 524 | {
|
---|
[26999] | 525 | VMMDevChangeMemBalloon *pReq;
|
---|
[27023] | 526 | uint32_t i;
|
---|
[26934] | 527 |
|
---|
[27023] | 528 | if (cBalloonChunks > pDevExt->MemBalloon.cMaxChunks)
|
---|
[26999] | 529 | {
|
---|
[58053] | 530 | LogRel(("vgdrvSetBalloonSizeKernel: illegal balloon size %u (max=%u)\n",
|
---|
[27106] | 531 | cBalloonChunks, pDevExt->MemBalloon.cMaxChunks));
|
---|
[26999] | 532 | return VERR_INVALID_PARAMETER;
|
---|
| 533 | }
|
---|
[26934] | 534 |
|
---|
[27023] | 535 | if (cBalloonChunks == pDevExt->MemBalloon.cMaxChunks)
|
---|
[26999] | 536 | return VINF_SUCCESS; /* nothing to do */
|
---|
[26934] | 537 |
|
---|
[27023] | 538 | if ( cBalloonChunks > pDevExt->MemBalloon.cChunks
|
---|
| 539 | && !pDevExt->MemBalloon.paMemObj)
|
---|
| 540 | {
|
---|
[27106] | 541 | pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAllocZ(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
|
---|
[27023] | 542 | if (!pDevExt->MemBalloon.paMemObj)
|
---|
| 543 | {
|
---|
[58053] | 544 | LogRel(("vgdrvSetBalloonSizeKernel: no memory for paMemObj!\n"));
|
---|
[27023] | 545 | return VERR_NO_MEMORY;
|
---|
| 546 | }
|
---|
| 547 | }
|
---|
| 548 |
|
---|
[68654] | 549 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, g_cbChangeMemBalloonReq, VMMDevReq_ChangeMemBalloon);
|
---|
[26999] | 550 | if (RT_FAILURE(rc))
|
---|
| 551 | return rc;
|
---|
| 552 |
|
---|
[27023] | 553 | if (cBalloonChunks > pDevExt->MemBalloon.cChunks)
|
---|
[26934] | 554 | {
|
---|
| 555 | /* inflate */
|
---|
[27023] | 556 | for (i = pDevExt->MemBalloon.cChunks; i < cBalloonChunks; i++)
|
---|
[26934] | 557 | {
|
---|
| 558 | rc = RTR0MemObjAllocPhysNC(&pDevExt->MemBalloon.paMemObj[i],
|
---|
[27023] | 559 | VMMDEV_MEMORY_BALLOON_CHUNK_SIZE, NIL_RTHCPHYS);
|
---|
[26934] | 560 | if (RT_FAILURE(rc))
|
---|
| 561 | {
|
---|
[27106] | 562 | if (rc == VERR_NOT_SUPPORTED)
|
---|
| 563 | {
|
---|
[27967] | 564 | /* not supported -- fall back to the R3-allocated memory. */
|
---|
| 565 | rc = VINF_SUCCESS;
|
---|
[27106] | 566 | pDevExt->MemBalloon.fUseKernelAPI = false;
|
---|
| 567 | Assert(pDevExt->MemBalloon.cChunks == 0);
|
---|
| 568 | Log(("VBoxGuestSetBalloonSizeKernel: PhysNC allocs not supported, falling back to R3 allocs.\n"));
|
---|
| 569 | }
|
---|
[27967] | 570 | /* else if (rc == VERR_NO_MEMORY || rc == VERR_NO_PHYS_MEMORY):
|
---|
| 571 | * cannot allocate more memory => don't try further, just stop here */
|
---|
| 572 | /* else: XXX what else can fail? VERR_MEMOBJ_INIT_FAILED for instance. just stop. */
|
---|
[26934] | 573 | break;
|
---|
| 574 | }
|
---|
| 575 |
|
---|
[58053] | 576 | rc = vgdrvBalloonInflate(&pDevExt->MemBalloon.paMemObj[i], pReq);
|
---|
[26934] | 577 | if (RT_FAILURE(rc))
|
---|
| 578 | {
|
---|
[27023] | 579 | Log(("vboxGuestSetBalloonSize(inflate): failed, rc=%Rrc!\n", rc));
|
---|
[27106] | 580 | RTR0MemObjFree(pDevExt->MemBalloon.paMemObj[i], true);
|
---|
| 581 | pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
|
---|
[26934] | 582 | break;
|
---|
| 583 | }
|
---|
| 584 | pDevExt->MemBalloon.cChunks++;
|
---|
| 585 | }
|
---|
| 586 | }
|
---|
| 587 | else
|
---|
| 588 | {
|
---|
| 589 | /* deflate */
|
---|
[27023] | 590 | for (i = pDevExt->MemBalloon.cChunks; i-- > cBalloonChunks;)
|
---|
[26934] | 591 | {
|
---|
[58053] | 592 | rc = vgdrvBalloonDeflate(&pDevExt->MemBalloon.paMemObj[i], pReq);
|
---|
[26934] | 593 | if (RT_FAILURE(rc))
|
---|
| 594 | {
|
---|
[27023] | 595 | Log(("vboxGuestSetBalloonSize(deflate): failed, rc=%Rrc!\n", rc));
|
---|
[26934] | 596 | break;
|
---|
| 597 | }
|
---|
| 598 | pDevExt->MemBalloon.cChunks--;
|
---|
| 599 | }
|
---|
| 600 | }
|
---|
[26999] | 601 |
|
---|
[68654] | 602 | VbglR0GRFree(&pReq->header);
|
---|
[26934] | 603 | }
|
---|
| 604 |
|
---|
[27967] | 605 | /*
|
---|
| 606 | * Set the handle-in-ring3 indicator. When set Ring-3 will have to work
|
---|
| 607 | * the balloon changes via the other API.
|
---|
| 608 | */
|
---|
| 609 | *pfHandleInR3 = pDevExt->MemBalloon.fUseKernelAPI ? false : true;
|
---|
[26934] | 610 |
|
---|
[26999] | 611 | return rc;
|
---|
| 612 | }
|
---|
| 613 |
|
---|
| 614 |
|
---|
| 615 | /**
|
---|
| 616 | * Inflate/deflate the balloon by one chunk.
|
---|
[27106] | 617 | *
|
---|
[58053] | 618 | * Worker for vgdrvIoCtl_ChangeMemoryBalloon - it takes the mutex.
|
---|
[27967] | 619 | *
|
---|
[27106] | 620 | * @returns VBox status code.
|
---|
| 621 | * @param pDevExt The device extension.
|
---|
| 622 | * @param pSession The session.
|
---|
[68550] | 623 | * @param pvChunk The address of the chunk to add to / remove from the
|
---|
| 624 | * balloon. (user space address)
|
---|
[27106] | 625 | * @param fInflate Inflate if true, deflate if false.
|
---|
[26999] | 626 | */
|
---|
[68550] | 627 | static int vgdrvSetBalloonSizeFromUser(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, RTR3PTR pvChunk, bool fInflate)
|
---|
[26999] | 628 | {
|
---|
| 629 | VMMDevChangeMemBalloon *pReq;
|
---|
[62853] | 630 | PRTR0MEMOBJ pMemObj = NULL;
|
---|
[26999] | 631 | int rc = VINF_SUCCESS;
|
---|
[27023] | 632 | uint32_t i;
|
---|
[62853] | 633 | RT_NOREF1(pSession);
|
---|
[26999] | 634 |
|
---|
[27023] | 635 | if (fInflate)
|
---|
[26999] | 636 | {
|
---|
[27118] | 637 | if ( pDevExt->MemBalloon.cChunks > pDevExt->MemBalloon.cMaxChunks - 1
|
---|
[27106] | 638 | || pDevExt->MemBalloon.cMaxChunks == 0 /* If called without first querying. */)
|
---|
[27023] | 639 | {
|
---|
[68550] | 640 | LogRel(("vgdrvSetBalloonSizeFromUser: cannot inflate balloon, already have %u chunks (max=%u)\n",
|
---|
[27118] | 641 | pDevExt->MemBalloon.cChunks, pDevExt->MemBalloon.cMaxChunks));
|
---|
[27023] | 642 | return VERR_INVALID_PARAMETER;
|
---|
| 643 | }
|
---|
| 644 |
|
---|
[27118] | 645 | if (!pDevExt->MemBalloon.paMemObj)
|
---|
[27023] | 646 | {
|
---|
[27118] | 647 | pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAlloc(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
|
---|
| 648 | if (!pDevExt->MemBalloon.paMemObj)
|
---|
[27023] | 649 | {
|
---|
[68550] | 650 | LogRel(("vgdrvSetBalloonSizeFromUser: no memory for paMemObj!\n"));
|
---|
[27023] | 651 | return VERR_NO_MEMORY;
|
---|
| 652 | }
|
---|
| 653 | for (i = 0; i < pDevExt->MemBalloon.cMaxChunks; i++)
|
---|
[27118] | 654 | pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
|
---|
[27023] | 655 | }
|
---|
[26999] | 656 | }
|
---|
[27023] | 657 | else
|
---|
[26999] | 658 | {
|
---|
[27118] | 659 | if (pDevExt->MemBalloon.cChunks == 0)
|
---|
[27023] | 660 | {
|
---|
[68550] | 661 | AssertMsgFailed(("vgdrvSetBalloonSizeFromUser: cannot decrease balloon, already at size 0\n"));
|
---|
[27023] | 662 | return VERR_INVALID_PARAMETER;
|
---|
| 663 | }
|
---|
[26999] | 664 | }
|
---|
| 665 |
|
---|
| 666 | /*
|
---|
| 667 | * Enumerate all memory objects and check if the object is already registered.
|
---|
| 668 | */
|
---|
[27023] | 669 | for (i = 0; i < pDevExt->MemBalloon.cMaxChunks; i++)
|
---|
[26999] | 670 | {
|
---|
| 671 | if ( fInflate
|
---|
[27023] | 672 | && !pMemObj
|
---|
[27118] | 673 | && pDevExt->MemBalloon.paMemObj[i] == NIL_RTR0MEMOBJ)
|
---|
| 674 | pMemObj = &pDevExt->MemBalloon.paMemObj[i]; /* found free object pointer */
|
---|
[68550] | 675 | if (RTR0MemObjAddressR3(pDevExt->MemBalloon.paMemObj[i]) == pvChunk)
|
---|
[26999] | 676 | {
|
---|
| 677 | if (fInflate)
|
---|
| 678 | return VERR_ALREADY_EXISTS; /* don't provide the same memory twice */
|
---|
[27118] | 679 | pMemObj = &pDevExt->MemBalloon.paMemObj[i];
|
---|
[26999] | 680 | break;
|
---|
| 681 | }
|
---|
| 682 | }
|
---|
| 683 | if (!pMemObj)
|
---|
| 684 | {
|
---|
| 685 | if (fInflate)
|
---|
[27118] | 686 | {
|
---|
| 687 | /* no free object pointer found -- should not happen */
|
---|
| 688 | return VERR_NO_MEMORY;
|
---|
| 689 | }
|
---|
| 690 |
|
---|
| 691 | /* cannot free this memory as it wasn't provided before */
|
---|
| 692 | return VERR_NOT_FOUND;
|
---|
[26999] | 693 | }
|
---|
| 694 |
|
---|
[27967] | 695 | /*
|
---|
[33540] | 696 | * Try inflate / default the balloon as requested.
|
---|
[27967] | 697 | */
|
---|
[68654] | 698 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, g_cbChangeMemBalloonReq, VMMDevReq_ChangeMemBalloon);
|
---|
[26999] | 699 | if (RT_FAILURE(rc))
|
---|
| 700 | return rc;
|
---|
[70873] | 701 | pReq->header.fRequestor = pSession->fRequestor;
|
---|
[26999] | 702 |
|
---|
[27106] | 703 | if (fInflate)
|
---|
[26999] | 704 | {
|
---|
[68550] | 705 | rc = RTR0MemObjLockUser(pMemObj, pvChunk, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE,
|
---|
[27106] | 706 | RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
|
---|
| 707 | if (RT_SUCCESS(rc))
|
---|
[26999] | 708 | {
|
---|
[58053] | 709 | rc = vgdrvBalloonInflate(pMemObj, pReq);
|
---|
[26999] | 710 | if (RT_SUCCESS(rc))
|
---|
[27118] | 711 | pDevExt->MemBalloon.cChunks++;
|
---|
[27106] | 712 | else
|
---|
[26999] | 713 | {
|
---|
[68550] | 714 | Log(("vgdrvSetBalloonSizeFromUser(inflate): failed, rc=%Rrc!\n", rc));
|
---|
[27106] | 715 | RTR0MemObjFree(*pMemObj, true);
|
---|
| 716 | *pMemObj = NIL_RTR0MEMOBJ;
|
---|
[26999] | 717 | }
|
---|
| 718 | }
|
---|
[27106] | 719 | }
|
---|
| 720 | else
|
---|
| 721 | {
|
---|
[58053] | 722 | rc = vgdrvBalloonDeflate(pMemObj, pReq);
|
---|
[27106] | 723 | if (RT_SUCCESS(rc))
|
---|
[27118] | 724 | pDevExt->MemBalloon.cChunks--;
|
---|
[26999] | 725 | else
|
---|
[68550] | 726 | Log(("vgdrvSetBalloonSizeFromUser(deflate): failed, rc=%Rrc!\n", rc));
|
---|
[27106] | 727 | }
|
---|
[26999] | 728 |
|
---|
[68654] | 729 | VbglR0GRFree(&pReq->header);
|
---|
[26934] | 730 | return rc;
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 |
|
---|
| 734 | /**
|
---|
[27023] | 735 | * Cleanup the memory balloon of a session.
|
---|
[27118] | 736 | *
|
---|
[27967] | 737 | * Will request the balloon mutex, so it must be valid and the caller must not
|
---|
| 738 | * own it already.
|
---|
| 739 | *
|
---|
[27118] | 740 | * @param pDevExt The device extension.
|
---|
[58089] | 741 | * @param pSession The session. Can be NULL at unload.
|
---|
[27023] | 742 | */
|
---|
[58053] | 743 | static void vgdrvCloseMemBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
|
---|
[27023] | 744 | {
|
---|
[27967] | 745 | RTSemFastMutexRequest(pDevExt->MemBalloon.hMtx);
|
---|
| 746 | if ( pDevExt->MemBalloon.pOwner == pSession
|
---|
| 747 | || pSession == NULL /*unload*/)
|
---|
[27023] | 748 | {
|
---|
[27967] | 749 | if (pDevExt->MemBalloon.paMemObj)
|
---|
[27023] | 750 | {
|
---|
[27967] | 751 | VMMDevChangeMemBalloon *pReq;
|
---|
[68654] | 752 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, g_cbChangeMemBalloonReq, VMMDevReq_ChangeMemBalloon);
|
---|
[27967] | 753 | if (RT_SUCCESS(rc))
|
---|
[27023] | 754 | {
|
---|
[70873] | 755 | /* fRequestor is kernel here, as we're cleaning up. */
|
---|
| 756 |
|
---|
[27967] | 757 | uint32_t i;
|
---|
| 758 | for (i = pDevExt->MemBalloon.cChunks; i-- > 0;)
|
---|
[27023] | 759 | {
|
---|
[58053] | 760 | rc = vgdrvBalloonDeflate(&pDevExt->MemBalloon.paMemObj[i], pReq);
|
---|
[27967] | 761 | if (RT_FAILURE(rc))
|
---|
| 762 | {
|
---|
[58053] | 763 | LogRel(("vgdrvCloseMemBalloon: Deflate failed with rc=%Rrc. Will leak %u chunks.\n",
|
---|
[54237] | 764 | rc, pDevExt->MemBalloon.cChunks));
|
---|
[27967] | 765 | break;
|
---|
| 766 | }
|
---|
| 767 | pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
|
---|
| 768 | pDevExt->MemBalloon.cChunks--;
|
---|
[27023] | 769 | }
|
---|
[68654] | 770 | VbglR0GRFree(&pReq->header);
|
---|
[27023] | 771 | }
|
---|
[27967] | 772 | else
|
---|
[58053] | 773 | LogRel(("vgdrvCloseMemBalloon: Failed to allocate VMMDev request buffer (rc=%Rrc). Will leak %u chunks.\n",
|
---|
[54237] | 774 | rc, pDevExt->MemBalloon.cChunks));
|
---|
[27967] | 775 | RTMemFree(pDevExt->MemBalloon.paMemObj);
|
---|
| 776 | pDevExt->MemBalloon.paMemObj = NULL;
|
---|
[27023] | 777 | }
|
---|
[27967] | 778 |
|
---|
| 779 | pDevExt->MemBalloon.pOwner = NULL;
|
---|
[27023] | 780 | }
|
---|
[27967] | 781 | RTSemFastMutexRelease(pDevExt->MemBalloon.hMtx);
|
---|
[27023] | 782 | }
|
---|
| 783 |
|
---|
[54608] | 784 | /** @} */
|
---|
[27023] | 785 |
|
---|
[54608] | 786 |
|
---|
| 787 |
|
---|
| 788 | /** @name Heartbeat
|
---|
| 789 | * @{
|
---|
| 790 | */
|
---|
| 791 |
|
---|
[27023] | 792 | /**
|
---|
[54608] | 793 | * Sends heartbeat to host.
|
---|
| 794 | *
|
---|
| 795 | * @returns VBox status code.
|
---|
| 796 | */
|
---|
[58053] | 797 | static int vgdrvHeartbeatSend(PVBOXGUESTDEVEXT pDevExt)
|
---|
[54608] | 798 | {
|
---|
| 799 | int rc;
|
---|
| 800 | if (pDevExt->pReqGuestHeartbeat)
|
---|
| 801 | {
|
---|
[68654] | 802 | rc = VbglR0GRPerform(pDevExt->pReqGuestHeartbeat);
|
---|
| 803 | Log3(("vgdrvHeartbeatSend: VbglR0GRPerform vgdrvHeartbeatSend completed with rc=%Rrc\n", rc));
|
---|
[54608] | 804 | }
|
---|
| 805 | else
|
---|
| 806 | rc = VERR_INVALID_STATE;
|
---|
| 807 | return rc;
|
---|
| 808 | }
|
---|
| 809 |
|
---|
| 810 |
|
---|
| 811 | /**
|
---|
| 812 | * Callback for heartbeat timer.
|
---|
| 813 | */
|
---|
[58053] | 814 | static DECLCALLBACK(void) vgdrvHeartbeatTimerHandler(PRTTIMER hTimer, void *pvUser, uint64_t iTick)
|
---|
[54608] | 815 | {
|
---|
| 816 | PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
|
---|
| 817 | int rc;
|
---|
| 818 | AssertReturnVoid(pDevExt);
|
---|
| 819 |
|
---|
[58053] | 820 | rc = vgdrvHeartbeatSend(pDevExt);
|
---|
[54608] | 821 | if (RT_FAILURE(rc))
|
---|
[58053] | 822 | Log(("HB Timer: vgdrvHeartbeatSend failed: rc=%Rrc\n", rc));
|
---|
[54608] | 823 |
|
---|
| 824 | NOREF(hTimer); NOREF(iTick);
|
---|
| 825 | }
|
---|
| 826 |
|
---|
| 827 |
|
---|
| 828 | /**
|
---|
| 829 | * Configure the host to check guest's heartbeat
|
---|
| 830 | * and get heartbeat interval from the host.
|
---|
| 831 | *
|
---|
| 832 | * @returns VBox status code.
|
---|
| 833 | * @param pDevExt The device extension.
|
---|
| 834 | * @param fEnabled Set true to enable guest heartbeat checks on host.
|
---|
| 835 | */
|
---|
[58053] | 836 | static int vgdrvHeartbeatHostConfigure(PVBOXGUESTDEVEXT pDevExt, bool fEnabled)
|
---|
[54608] | 837 | {
|
---|
| 838 | VMMDevReqHeartbeat *pReq;
|
---|
[68654] | 839 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_HeartbeatConfigure);
|
---|
| 840 | Log(("vgdrvHeartbeatHostConfigure: VbglR0GRAlloc vgdrvHeartbeatHostConfigure completed with rc=%Rrc\n", rc));
|
---|
[54608] | 841 | if (RT_SUCCESS(rc))
|
---|
| 842 | {
|
---|
| 843 | pReq->fEnabled = fEnabled;
|
---|
| 844 | pReq->cNsInterval = 0;
|
---|
[68654] | 845 | rc = VbglR0GRPerform(&pReq->header);
|
---|
| 846 | Log(("vgdrvHeartbeatHostConfigure: VbglR0GRPerform vgdrvHeartbeatHostConfigure completed with rc=%Rrc\n", rc));
|
---|
[54608] | 847 | pDevExt->cNsHeartbeatInterval = pReq->cNsInterval;
|
---|
[68654] | 848 | VbglR0GRFree(&pReq->header);
|
---|
[54608] | 849 | }
|
---|
| 850 | return rc;
|
---|
| 851 | }
|
---|
| 852 |
|
---|
| 853 |
|
---|
| 854 | /**
|
---|
| 855 | * Initializes the heartbeat timer.
|
---|
| 856 | *
|
---|
| 857 | * This feature may be disabled by the host.
|
---|
| 858 | *
|
---|
| 859 | * @returns VBox status (ignored).
|
---|
| 860 | * @param pDevExt The device extension.
|
---|
| 861 | */
|
---|
[58053] | 862 | static int vgdrvHeartbeatInit(PVBOXGUESTDEVEXT pDevExt)
|
---|
[54608] | 863 | {
|
---|
| 864 | /*
|
---|
| 865 | * Make sure that heartbeat checking is disabled.
|
---|
| 866 | */
|
---|
[58053] | 867 | int rc = vgdrvHeartbeatHostConfigure(pDevExt, false);
|
---|
[54608] | 868 | if (RT_SUCCESS(rc))
|
---|
| 869 | {
|
---|
[58053] | 870 | rc = vgdrvHeartbeatHostConfigure(pDevExt, true);
|
---|
[54608] | 871 | if (RT_SUCCESS(rc))
|
---|
| 872 | {
|
---|
| 873 | /*
|
---|
| 874 | * Preallocate the request to use it from the timer callback because:
|
---|
[68654] | 875 | * 1) on Windows VbglR0GRAlloc must be called at IRQL <= APC_LEVEL
|
---|
[54608] | 876 | * and the timer callback runs at DISPATCH_LEVEL;
|
---|
| 877 | * 2) avoid repeated allocations.
|
---|
| 878 | */
|
---|
[68654] | 879 | rc = VbglR0GRAlloc(&pDevExt->pReqGuestHeartbeat, sizeof(*pDevExt->pReqGuestHeartbeat), VMMDevReq_GuestHeartbeat);
|
---|
[54608] | 880 | if (RT_SUCCESS(rc))
|
---|
| 881 | {
|
---|
[58053] | 882 | LogRel(("vgdrvHeartbeatInit: Setting up heartbeat to trigger every %RU64 milliseconds\n",
|
---|
[55275] | 883 | pDevExt->cNsHeartbeatInterval / RT_NS_1MS));
|
---|
[54608] | 884 | rc = RTTimerCreateEx(&pDevExt->pHeartbeatTimer, pDevExt->cNsHeartbeatInterval, 0 /*fFlags*/,
|
---|
[58053] | 885 | (PFNRTTIMER)vgdrvHeartbeatTimerHandler, pDevExt);
|
---|
[54608] | 886 | if (RT_SUCCESS(rc))
|
---|
| 887 | {
|
---|
| 888 | rc = RTTimerStart(pDevExt->pHeartbeatTimer, 0);
|
---|
| 889 | if (RT_SUCCESS(rc))
|
---|
| 890 | return VINF_SUCCESS;
|
---|
| 891 |
|
---|
[58053] | 892 | LogRel(("vgdrvHeartbeatInit: Heartbeat timer failed to start, rc=%Rrc\n", rc));
|
---|
[54608] | 893 | }
|
---|
| 894 | else
|
---|
[58053] | 895 | LogRel(("vgdrvHeartbeatInit: Failed to create heartbeat timer: %Rrc\n", rc));
|
---|
[54608] | 896 |
|
---|
[68654] | 897 | VbglR0GRFree(pDevExt->pReqGuestHeartbeat);
|
---|
[54608] | 898 | pDevExt->pReqGuestHeartbeat = NULL;
|
---|
| 899 | }
|
---|
| 900 | else
|
---|
[68654] | 901 | LogRel(("vgdrvHeartbeatInit: VbglR0GRAlloc(VMMDevReq_GuestHeartbeat): %Rrc\n", rc));
|
---|
[54608] | 902 |
|
---|
[58053] | 903 | LogRel(("vgdrvHeartbeatInit: Failed to set up the timer, guest heartbeat is disabled\n"));
|
---|
| 904 | vgdrvHeartbeatHostConfigure(pDevExt, false);
|
---|
[54608] | 905 | }
|
---|
| 906 | else
|
---|
[58053] | 907 | LogRel(("vgdrvHeartbeatInit: Failed to configure host for heartbeat checking: rc=%Rrc\n", rc));
|
---|
[54608] | 908 | }
|
---|
| 909 | return rc;
|
---|
| 910 | }
|
---|
| 911 |
|
---|
| 912 | /** @} */
|
---|
| 913 |
|
---|
| 914 |
|
---|
| 915 | /**
|
---|
| 916 | * Helper to reinit the VMMDev communication after hibernation.
|
---|
| 917 | *
|
---|
| 918 | * @returns VBox status code.
|
---|
| 919 | * @param pDevExt The device extension.
|
---|
| 920 | * @param enmOSType The OS type.
|
---|
| 921 | *
|
---|
| 922 | * @todo Call this on all platforms, not just windows.
|
---|
| 923 | */
|
---|
[58053] | 924 | int VGDrvCommonReinitDevExtAfterHibernation(PVBOXGUESTDEVEXT pDevExt, VBOXOSTYPE enmOSType)
|
---|
[54608] | 925 | {
|
---|
[58053] | 926 | int rc = vgdrvReportGuestInfo(enmOSType);
|
---|
[54608] | 927 | if (RT_SUCCESS(rc))
|
---|
| 928 | {
|
---|
[58053] | 929 | rc = vgdrvReportDriverStatus(true /* Driver is active */);
|
---|
[54608] | 930 | if (RT_FAILURE(rc))
|
---|
[58053] | 931 | Log(("VGDrvCommonReinitDevExtAfterHibernation: could not report guest driver status, rc=%Rrc\n", rc));
|
---|
[54608] | 932 | }
|
---|
| 933 | else
|
---|
[58053] | 934 | Log(("VGDrvCommonReinitDevExtAfterHibernation: could not report guest information to host, rc=%Rrc\n", rc));
|
---|
| 935 | LogFlow(("VGDrvCommonReinitDevExtAfterHibernation: returned with rc=%Rrc\n", rc));
|
---|
[62853] | 936 | RT_NOREF1(pDevExt);
|
---|
[54608] | 937 | return rc;
|
---|
| 938 | }
|
---|
| 939 |
|
---|
| 940 |
|
---|
| 941 | /**
|
---|
[70223] | 942 | * Initializes the release logger (debug is implicit), if configured.
|
---|
[6032] | 943 | *
|
---|
[70223] | 944 | * @returns IPRT status code.
|
---|
[3657] | 945 | */
|
---|
[70223] | 946 | int VGDrvCommonInitLoggers(void)
|
---|
[3657] | 947 | {
|
---|
[48034] | 948 | #ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
|
---|
[3657] | 949 | /*
|
---|
[48034] | 950 | * Create the release log.
|
---|
| 951 | */
|
---|
| 952 | static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
|
---|
| 953 | PRTLOGGER pRelLogger;
|
---|
[70223] | 954 | int rc = RTLogCreate(&pRelLogger, 0 /*fFlags*/, "all", "VBOXGUEST_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
|
---|
| 955 | RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
|
---|
[48034] | 956 | if (RT_SUCCESS(rc))
|
---|
| 957 | RTLogRelSetDefaultInstance(pRelLogger);
|
---|
| 958 | /** @todo Add native hook for getting logger config parameters and setting
|
---|
[54239] | 959 | * them. On linux we should use the module parameter stuff... */
|
---|
[70223] | 960 | return rc;
|
---|
| 961 | #else
|
---|
| 962 | return VINF_SUCCESS;
|
---|
[48034] | 963 | #endif
|
---|
[70223] | 964 | }
|
---|
[48034] | 965 |
|
---|
[70223] | 966 |
|
---|
| 967 | /**
|
---|
| 968 | * Destroys the loggers.
|
---|
| 969 | */
|
---|
| 970 | void VGDrvCommonDestroyLoggers(void)
|
---|
| 971 | {
|
---|
| 972 | #ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
|
---|
| 973 | RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
|
---|
| 974 | RTLogDestroy(RTLogSetDefaultInstance(NULL));
|
---|
[21376] | 975 | #endif
|
---|
[70223] | 976 | }
|
---|
[21376] | 977 |
|
---|
[70223] | 978 |
|
---|
| 979 | /**
|
---|
| 980 | * Initialize the device extension fundament.
|
---|
| 981 | *
|
---|
| 982 | * There are no device resources at this point, VGDrvCommonInitDevExtResources
|
---|
| 983 | * should be called when they are available.
|
---|
| 984 | *
|
---|
| 985 | * @returns VBox status code.
|
---|
| 986 | * @param pDevExt The device extension to init.
|
---|
| 987 | */
|
---|
| 988 | int VGDrvCommonInitDevExtFundament(PVBOXGUESTDEVEXT pDevExt)
|
---|
| 989 | {
|
---|
| 990 | int rc;
|
---|
| 991 | AssertMsg( pDevExt->uInitState != VBOXGUESTDEVEXT_INIT_STATE_FUNDAMENT
|
---|
| 992 | && pDevExt->uInitState != VBOXGUESTDEVEXT_INIT_STATE_RESOURCES, ("uInitState=%#x\n", pDevExt->uInitState));
|
---|
| 993 |
|
---|
[21376] | 994 | /*
|
---|
[33540] | 995 | * Initialize the data.
|
---|
[3657] | 996 | */
|
---|
[70223] | 997 | pDevExt->IOPortBase = UINT16_MAX;
|
---|
[100267] | 998 | pDevExt->pMmioReq = NULL;
|
---|
| 999 | pDevExt->pMmioReqFast = NULL;
|
---|
[3657] | 1000 | pDevExt->pVMMDevMemory = NULL;
|
---|
[21498] | 1001 | pDevExt->hGuestMappings = NIL_RTR0MEMOBJ;
|
---|
[27967] | 1002 | pDevExt->EventSpinlock = NIL_RTSPINLOCK;
|
---|
[75588] | 1003 | pDevExt->fHostFeatures = 0;
|
---|
[3657] | 1004 | pDevExt->pIrqAckEvents = NULL;
|
---|
[21376] | 1005 | pDevExt->PhysIrqAckEvents = NIL_RTCCPHYS;
|
---|
[32449] | 1006 | RTListInit(&pDevExt->WaitList);
|
---|
[11820] | 1007 | #ifdef VBOX_WITH_HGCM
|
---|
[32449] | 1008 | RTListInit(&pDevExt->HGCMWaitList);
|
---|
[6032] | 1009 | #endif
|
---|
[32449] | 1010 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
| 1011 | RTListInit(&pDevExt->WakeUpList);
|
---|
| 1012 | #endif
|
---|
| 1013 | RTListInit(&pDevExt->WokenUpList);
|
---|
| 1014 | RTListInit(&pDevExt->FreeList);
|
---|
[50523] | 1015 | RTListInit(&pDevExt->SessionList);
|
---|
[54601] | 1016 | pDevExt->cSessions = 0;
|
---|
[40198] | 1017 | pDevExt->fLoggingEnabled = false;
|
---|
[3657] | 1018 | pDevExt->f32PendingEvents = 0;
|
---|
[27967] | 1019 | pDevExt->u32MousePosChangedSeq = 0;
|
---|
| 1020 | pDevExt->SessionSpinlock = NIL_RTSPINLOCK;
|
---|
| 1021 | pDevExt->MemBalloon.hMtx = NIL_RTSEMFASTMUTEX;
|
---|
| 1022 | pDevExt->MemBalloon.cChunks = 0;
|
---|
| 1023 | pDevExt->MemBalloon.cMaxChunks = 0;
|
---|
| 1024 | pDevExt->MemBalloon.fUseKernelAPI = true;
|
---|
| 1025 | pDevExt->MemBalloon.paMemObj = NULL;
|
---|
| 1026 | pDevExt->MemBalloon.pOwner = NULL;
|
---|
[68550] | 1027 | pDevExt->pfnMouseNotifyCallback = NULL;
|
---|
| 1028 | pDevExt->pvMouseNotifyCallbackArg = NULL;
|
---|
[53077] | 1029 | pDevExt->pReqGuestHeartbeat = NULL;
|
---|
[3657] | 1030 |
|
---|
[70223] | 1031 | pDevExt->fFixedEvents = 0;
|
---|
[58053] | 1032 | vgdrvBitUsageTrackerClear(&pDevExt->EventFilterTracker);
|
---|
[54606] | 1033 | pDevExt->fEventFilterHost = UINT32_MAX; /* forces a report */
|
---|
| 1034 |
|
---|
[58053] | 1035 | vgdrvBitUsageTrackerClear(&pDevExt->MouseStatusTracker);
|
---|
[54606] | 1036 | pDevExt->fMouseStatusHost = UINT32_MAX; /* forces a report */
|
---|
| 1037 |
|
---|
[54613] | 1038 | pDevExt->fAcquireModeGuestCaps = 0;
|
---|
| 1039 | pDevExt->fSetModeGuestCaps = 0;
|
---|
| 1040 | pDevExt->fAcquiredGuestCaps = 0;
|
---|
[58053] | 1041 | vgdrvBitUsageTrackerClear(&pDevExt->SetGuestCapsTracker);
|
---|
[54606] | 1042 | pDevExt->fGuestCapsHost = UINT32_MAX; /* forces a report */
|
---|
| 1043 |
|
---|
[3657] | 1044 | /*
|
---|
[70223] | 1045 | * Create the wait and session spinlocks as well as the ballooning mutex.
|
---|
| 1046 | */
|
---|
| 1047 | rc = RTSpinlockCreate(&pDevExt->EventSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestEvent");
|
---|
| 1048 | if (RT_SUCCESS(rc))
|
---|
| 1049 | {
|
---|
| 1050 | rc = RTSpinlockCreate(&pDevExt->SessionSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestSession");
|
---|
| 1051 | if (RT_SUCCESS(rc))
|
---|
| 1052 | {
|
---|
| 1053 | rc = RTSemFastMutexCreate(&pDevExt->MemBalloon.hMtx);
|
---|
| 1054 | if (RT_SUCCESS(rc))
|
---|
| 1055 | {
|
---|
| 1056 | pDevExt->uInitState = VBOXGUESTDEVEXT_INIT_STATE_FUNDAMENT;
|
---|
| 1057 | return VINF_SUCCESS;
|
---|
| 1058 | }
|
---|
| 1059 |
|
---|
| 1060 | LogRel(("VGDrvCommonInitDevExt: failed to create mutex, rc=%Rrc!\n", rc));
|
---|
| 1061 | RTSpinlockDestroy(pDevExt->SessionSpinlock);
|
---|
| 1062 | }
|
---|
| 1063 | else
|
---|
| 1064 | LogRel(("VGDrvCommonInitDevExt: failed to create spinlock, rc=%Rrc!\n", rc));
|
---|
| 1065 | RTSpinlockDestroy(pDevExt->EventSpinlock);
|
---|
| 1066 | }
|
---|
| 1067 | else
|
---|
| 1068 | LogRel(("VGDrvCommonInitDevExt: failed to create spinlock, rc=%Rrc!\n", rc));
|
---|
| 1069 |
|
---|
| 1070 | pDevExt->uInitState = 0;
|
---|
| 1071 | return rc;
|
---|
| 1072 | }
|
---|
| 1073 |
|
---|
| 1074 |
|
---|
| 1075 | /**
|
---|
| 1076 | * Counter to VGDrvCommonInitDevExtFundament.
|
---|
| 1077 | *
|
---|
| 1078 | * @param pDevExt The device extension.
|
---|
| 1079 | */
|
---|
| 1080 | void VGDrvCommonDeleteDevExtFundament(PVBOXGUESTDEVEXT pDevExt)
|
---|
| 1081 | {
|
---|
| 1082 | int rc2;
|
---|
| 1083 | AssertMsgReturnVoid(pDevExt->uInitState == VBOXGUESTDEVEXT_INIT_STATE_FUNDAMENT, ("uInitState=%#x\n", pDevExt->uInitState));
|
---|
| 1084 | pDevExt->uInitState = VBOXGUESTDEVEXT_INIT_STATE_DELETED;
|
---|
| 1085 |
|
---|
| 1086 | rc2 = RTSemFastMutexDestroy(pDevExt->MemBalloon.hMtx); AssertRC(rc2);
|
---|
| 1087 | rc2 = RTSpinlockDestroy(pDevExt->EventSpinlock); AssertRC(rc2);
|
---|
| 1088 | rc2 = RTSpinlockDestroy(pDevExt->SessionSpinlock); AssertRC(rc2);
|
---|
| 1089 | }
|
---|
| 1090 |
|
---|
| 1091 |
|
---|
| 1092 | /**
|
---|
| 1093 | * Initializes the VBoxGuest device extension resource parts.
|
---|
| 1094 | *
|
---|
| 1095 | * The native code locates the VMMDev on the PCI bus and retrieve the MMIO and
|
---|
| 1096 | * I/O port ranges, this function will take care of mapping the MMIO memory (if
|
---|
| 1097 | * present). Upon successful return the native code should set up the interrupt
|
---|
| 1098 | * handler.
|
---|
| 1099 | *
|
---|
| 1100 | * @returns VBox status code.
|
---|
| 1101 | *
|
---|
| 1102 | * @param pDevExt The device extension. Allocated by the native code.
|
---|
| 1103 | * @param IOPortBase The base of the I/O port range.
|
---|
[100267] | 1104 | * @param pvMmioReq The base of the MMIO request region.
|
---|
[70223] | 1105 | * @param pvMMIOBase The base of the MMIO memory mapping.
|
---|
| 1106 | * This is optional, pass NULL if not present.
|
---|
| 1107 | * @param cbMMIO The size of the MMIO memory mapping.
|
---|
| 1108 | * This is optional, pass 0 if not present.
|
---|
| 1109 | * @param enmOSType The guest OS type to report to the VMMDev.
|
---|
| 1110 | * @param fFixedEvents Events that will be enabled upon init and no client
|
---|
| 1111 | * will ever be allowed to mask.
|
---|
| 1112 | */
|
---|
| 1113 | int VGDrvCommonInitDevExtResources(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase,
|
---|
[100267] | 1114 | void *pvMmioReq, void *pvMMIOBase, uint32_t cbMMIO,
|
---|
| 1115 | VBOXOSTYPE enmOSType, uint32_t fFixedEvents)
|
---|
[70223] | 1116 | {
|
---|
| 1117 | int rc;
|
---|
| 1118 | AssertMsgReturn(pDevExt->uInitState == VBOXGUESTDEVEXT_INIT_STATE_FUNDAMENT, ("uInitState=%#x\n", pDevExt->uInitState),
|
---|
| 1119 | VERR_INVALID_STATE);
|
---|
| 1120 |
|
---|
| 1121 | /*
|
---|
[6032] | 1122 | * If there is an MMIO region validate the version and size.
|
---|
[3657] | 1123 | */
|
---|
[6032] | 1124 | if (pvMMIOBase)
|
---|
[3657] | 1125 | {
|
---|
[21118] | 1126 | VMMDevMemory *pVMMDev = (VMMDevMemory *)pvMMIOBase;
|
---|
[6032] | 1127 | Assert(cbMMIO);
|
---|
| 1128 | if ( pVMMDev->u32Version == VMMDEV_MEMORY_VERSION
|
---|
| 1129 | && pVMMDev->u32Size >= 32
|
---|
| 1130 | && pVMMDev->u32Size <= cbMMIO)
|
---|
| 1131 | {
|
---|
| 1132 | pDevExt->pVMMDevMemory = pVMMDev;
|
---|
[70223] | 1133 | Log(("VGDrvCommonInitDevExtResources: VMMDevMemory: mapping=%p size=%#RX32 (%#RX32) version=%#RX32\n",
|
---|
[54237] | 1134 | pVMMDev, pVMMDev->u32Size, cbMMIO, pVMMDev->u32Version));
|
---|
[6032] | 1135 | }
|
---|
| 1136 | else /* try live without it. */
|
---|
[70223] | 1137 | LogRel(("VGDrvCommonInitDevExtResources: Bogus VMMDev memory; u32Version=%RX32 (expected %RX32) u32Size=%RX32 (expected <= %RX32)\n",
|
---|
[54237] | 1138 | pVMMDev->u32Version, VMMDEV_MEMORY_VERSION, pVMMDev->u32Size, cbMMIO));
|
---|
[3657] | 1139 | }
|
---|
| 1140 |
|
---|
| 1141 | /*
|
---|
| 1142 | * Initialize the guest library and report the guest info back to VMMDev,
|
---|
[6032] | 1143 | * set the interrupt control filter mask, and fixate the guest mappings
|
---|
[3657] | 1144 | * made by the VMM.
|
---|
| 1145 | */
|
---|
[100267] | 1146 | pDevExt->IOPortBase = IOPortBase;
|
---|
| 1147 | pDevExt->pMmioReq = (uintptr_t volatile *)pvMmioReq;
|
---|
[100363] | 1148 | pDevExt->pMmioReqFast = pvMmioReq ? (uint32_t volatile *)((uintptr_t)pvMmioReq + VMMDEV_MMIO_OFF_REQUEST_FAST) : NULL;
|
---|
[100267] | 1149 | rc = VbglR0InitPrimary(pDevExt->IOPortBase, pDevExt->pMmioReq, (VMMDevMemory *)pDevExt->pVMMDevMemory, &pDevExt->fHostFeatures);
|
---|
[3657] | 1150 | if (RT_SUCCESS(rc))
|
---|
| 1151 | {
|
---|
[75588] | 1152 | VMMDevRequestHeader *pAckReq = NULL;
|
---|
| 1153 | rc = VbglR0GRAlloc(&pAckReq, sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
|
---|
[3657] | 1154 | if (RT_SUCCESS(rc))
|
---|
| 1155 | {
|
---|
[75588] | 1156 | pDevExt->PhysIrqAckEvents = VbglR0PhysHeapGetPhysAddr(pAckReq);
|
---|
[100267] | 1157 | Assert( pDevExt->PhysIrqAckEvents != 0
|
---|
| 1158 | && pDevExt->PhysIrqAckEvents == (uintptr_t)pDevExt->PhysIrqAckEvents);
|
---|
[75588] | 1159 | ASMCompilerBarrier(); /* linux + solaris already have IRQs hooked up at this point, so take care. */
|
---|
| 1160 | pDevExt->pIrqAckEvents = (VMMDevEvents *)pAckReq;
|
---|
[21376] | 1161 |
|
---|
[58053] | 1162 | rc = vgdrvReportGuestInfo(enmOSType);
|
---|
[3657] | 1163 | if (RT_SUCCESS(rc))
|
---|
| 1164 | {
|
---|
[54601] | 1165 | /*
|
---|
[54612] | 1166 | * Set the fixed event and make sure the host doesn't have any lingering
|
---|
| 1167 | * the guest capabilities or mouse status bits set.
|
---|
[54601] | 1168 | */
|
---|
[70223] | 1169 | #ifdef VBOX_WITH_HGCM
|
---|
| 1170 | fFixedEvents |= VMMDEV_EVENT_HGCM;
|
---|
| 1171 | #endif
|
---|
| 1172 | pDevExt->fFixedEvents = fFixedEvents;
|
---|
| 1173 | rc = vgdrvResetEventFilterOnHost(pDevExt, fFixedEvents);
|
---|
[3657] | 1174 | if (RT_SUCCESS(rc))
|
---|
| 1175 | {
|
---|
[58053] | 1176 | rc = vgdrvResetCapabilitiesOnHost(pDevExt);
|
---|
[52789] | 1177 | if (RT_SUCCESS(rc))
|
---|
| 1178 | {
|
---|
[58053] | 1179 | rc = vgdrvResetMouseStatusOnHost(pDevExt);
|
---|
[54612] | 1180 | if (RT_SUCCESS(rc))
|
---|
| 1181 | {
|
---|
| 1182 | /*
|
---|
| 1183 | * Initialize stuff which may fail without requiring the driver init to fail.
|
---|
| 1184 | */
|
---|
[58053] | 1185 | vgdrvInitFixateGuestMappings(pDevExt);
|
---|
| 1186 | vgdrvHeartbeatInit(pDevExt);
|
---|
[53077] | 1187 |
|
---|
[54612] | 1188 | /*
|
---|
| 1189 | * Done!
|
---|
| 1190 | */
|
---|
[58053] | 1191 | rc = vgdrvReportDriverStatus(true /* Driver is active */);
|
---|
[54612] | 1192 | if (RT_FAILURE(rc))
|
---|
[70223] | 1193 | LogRel(("VGDrvCommonInitDevExtResources: VBoxReportGuestDriverStatus failed, rc=%Rrc\n", rc));
|
---|
[53077] | 1194 |
|
---|
[70223] | 1195 | pDevExt->uInitState = VBOXGUESTDEVEXT_INIT_STATE_RESOURCES;
|
---|
| 1196 | LogFlowFunc(("VGDrvCommonInitDevExtResources: returns success\n"));
|
---|
[54612] | 1197 | return VINF_SUCCESS;
|
---|
| 1198 | }
|
---|
[70223] | 1199 | LogRel(("VGDrvCommonInitDevExtResources: failed to clear mouse status: rc=%Rrc\n", rc));
|
---|
[52789] | 1200 | }
|
---|
[54612] | 1201 | else
|
---|
[70223] | 1202 | LogRel(("VGDrvCommonInitDevExtResources: failed to clear guest capabilities: rc=%Rrc\n", rc));
|
---|
[3657] | 1203 | }
|
---|
[54612] | 1204 | else
|
---|
[70223] | 1205 | LogRel(("VGDrvCommonInitDevExtResources: failed to set fixed event filter: rc=%Rrc\n", rc));
|
---|
| 1206 | pDevExt->fFixedEvents = 0;
|
---|
[3657] | 1207 | }
|
---|
[26631] | 1208 | else
|
---|
[70223] | 1209 | LogRel(("VGDrvCommonInitDevExtResources: vgdrvReportGuestInfo failed: rc=%Rrc\n", rc));
|
---|
[68654] | 1210 | VbglR0GRFree((VMMDevRequestHeader *)pDevExt->pIrqAckEvents);
|
---|
[3657] | 1211 | }
|
---|
| 1212 | else
|
---|
[70223] | 1213 | LogRel(("VGDrvCommonInitDevExtResources: VbglR0GRAlloc failed: rc=%Rrc\n", rc));
|
---|
[3657] | 1214 |
|
---|
[68550] | 1215 | VbglR0TerminatePrimary();
|
---|
[3657] | 1216 | }
|
---|
| 1217 | else
|
---|
[70223] | 1218 | LogRel(("VGDrvCommonInitDevExtResources: VbglR0InitPrimary failed: rc=%Rrc\n", rc));
|
---|
| 1219 | pDevExt->IOPortBase = UINT16_MAX;
|
---|
| 1220 | return rc;
|
---|
| 1221 | }
|
---|
[3657] | 1222 |
|
---|
[48034] | 1223 |
|
---|
[70223] | 1224 | /**
|
---|
| 1225 | * Deletes all the items in a wait chain.
|
---|
| 1226 | * @param pList The head of the chain.
|
---|
| 1227 | */
|
---|
| 1228 | static void vgdrvDeleteWaitList(PRTLISTNODE pList)
|
---|
| 1229 | {
|
---|
| 1230 | while (!RTListIsEmpty(pList))
|
---|
| 1231 | {
|
---|
| 1232 | int rc2;
|
---|
| 1233 | PVBOXGUESTWAIT pWait = RTListGetFirst(pList, VBOXGUESTWAIT, ListNode);
|
---|
| 1234 | RTListNodeRemove(&pWait->ListNode);
|
---|
| 1235 |
|
---|
| 1236 | rc2 = RTSemEventMultiDestroy(pWait->Event); AssertRC(rc2);
|
---|
| 1237 | pWait->Event = NIL_RTSEMEVENTMULTI;
|
---|
| 1238 | pWait->pSession = NULL;
|
---|
| 1239 | RTMemFree(pWait);
|
---|
| 1240 | }
|
---|
| 1241 | }
|
---|
| 1242 |
|
---|
| 1243 |
|
---|
| 1244 | /**
|
---|
| 1245 | * Counter to VGDrvCommonInitDevExtResources.
|
---|
| 1246 | *
|
---|
| 1247 | * @param pDevExt The device extension.
|
---|
| 1248 | */
|
---|
| 1249 | void VGDrvCommonDeleteDevExtResources(PVBOXGUESTDEVEXT pDevExt)
|
---|
| 1250 | {
|
---|
| 1251 | Log(("VGDrvCommonDeleteDevExtResources:\n"));
|
---|
| 1252 | AssertMsgReturnVoid(pDevExt->uInitState == VBOXGUESTDEVEXT_INIT_STATE_RESOURCES, ("uInitState=%#x\n", pDevExt->uInitState));
|
---|
| 1253 | pDevExt->uInitState = VBOXGUESTDEVEXT_INIT_STATE_FUNDAMENT;
|
---|
| 1254 |
|
---|
| 1255 | /*
|
---|
| 1256 | * Stop and destroy HB timer and disable host heartbeat checking.
|
---|
| 1257 | */
|
---|
| 1258 | if (pDevExt->pHeartbeatTimer)
|
---|
| 1259 | {
|
---|
| 1260 | RTTimerDestroy(pDevExt->pHeartbeatTimer);
|
---|
| 1261 | vgdrvHeartbeatHostConfigure(pDevExt, false);
|
---|
| 1262 | }
|
---|
| 1263 |
|
---|
| 1264 | VbglR0GRFree(pDevExt->pReqGuestHeartbeat);
|
---|
| 1265 | pDevExt->pReqGuestHeartbeat = NULL;
|
---|
| 1266 |
|
---|
| 1267 | /*
|
---|
| 1268 | * Clean up the bits that involves the host first.
|
---|
| 1269 | */
|
---|
| 1270 | vgdrvTermUnfixGuestMappings(pDevExt);
|
---|
| 1271 | if (!RTListIsEmpty(&pDevExt->SessionList))
|
---|
| 1272 | {
|
---|
| 1273 | LogRelFunc(("session list not empty!\n"));
|
---|
| 1274 | RTListInit(&pDevExt->SessionList);
|
---|
| 1275 | }
|
---|
| 1276 |
|
---|
| 1277 | /*
|
---|
| 1278 | * Update the host flags (mouse status etc) not to reflect this session.
|
---|
| 1279 | */
|
---|
| 1280 | pDevExt->fFixedEvents = 0;
|
---|
| 1281 | vgdrvResetEventFilterOnHost(pDevExt, 0 /*fFixedEvents*/);
|
---|
| 1282 | vgdrvResetCapabilitiesOnHost(pDevExt);
|
---|
| 1283 | vgdrvResetMouseStatusOnHost(pDevExt);
|
---|
| 1284 |
|
---|
| 1285 | vgdrvCloseMemBalloon(pDevExt, (PVBOXGUESTSESSION)NULL);
|
---|
| 1286 |
|
---|
| 1287 | /*
|
---|
[75588] | 1288 | * No more IRQs.
|
---|
| 1289 | */
|
---|
| 1290 | pDevExt->pIrqAckEvents = NULL; /* Will be freed by VbglR0TerminatePrimary. */
|
---|
| 1291 | ASMAtomicWriteU32(&pDevExt->fHostFeatures, 0);
|
---|
| 1292 |
|
---|
| 1293 | /*
|
---|
[70223] | 1294 | * Cleanup all the other resources.
|
---|
| 1295 | */
|
---|
| 1296 | vgdrvDeleteWaitList(&pDevExt->WaitList);
|
---|
| 1297 | #ifdef VBOX_WITH_HGCM
|
---|
| 1298 | vgdrvDeleteWaitList(&pDevExt->HGCMWaitList);
|
---|
[48034] | 1299 | #endif
|
---|
[70223] | 1300 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
| 1301 | vgdrvDeleteWaitList(&pDevExt->WakeUpList);
|
---|
| 1302 | #endif
|
---|
| 1303 | vgdrvDeleteWaitList(&pDevExt->WokenUpList);
|
---|
| 1304 | vgdrvDeleteWaitList(&pDevExt->FreeList);
|
---|
| 1305 |
|
---|
| 1306 | VbglR0TerminatePrimary();
|
---|
| 1307 |
|
---|
| 1308 |
|
---|
| 1309 | pDevExt->pVMMDevMemory = NULL;
|
---|
| 1310 | pDevExt->IOPortBase = 0;
|
---|
| 1311 | }
|
---|
| 1312 |
|
---|
| 1313 |
|
---|
| 1314 | /**
|
---|
| 1315 | * Initializes the VBoxGuest device extension when the device driver is loaded.
|
---|
| 1316 | *
|
---|
| 1317 | * The native code locates the VMMDev on the PCI bus and retrieve the MMIO and
|
---|
| 1318 | * I/O port ranges, this function will take care of mapping the MMIO memory (if
|
---|
| 1319 | * present). Upon successful return the native code should set up the interrupt
|
---|
| 1320 | * handler.
|
---|
| 1321 | *
|
---|
| 1322 | * Instead of calling this method, the host specific code choose to perform a
|
---|
| 1323 | * more granular initialization using:
|
---|
| 1324 | * 1. VGDrvCommonInitLoggers
|
---|
| 1325 | * 2. VGDrvCommonInitDevExtFundament
|
---|
| 1326 | * 3. VGDrvCommonInitDevExtResources
|
---|
| 1327 | *
|
---|
| 1328 | * @returns VBox status code.
|
---|
| 1329 | *
|
---|
| 1330 | * @param pDevExt The device extension. Allocated by the native code.
|
---|
| 1331 | * @param IOPortBase The base of the I/O port range.
|
---|
[100267] | 1332 | * @param pvMmioReq The base of the MMIO request region.
|
---|
[70223] | 1333 | * @param pvMMIOBase The base of the MMIO memory mapping.
|
---|
| 1334 | * This is optional, pass NULL if not present.
|
---|
| 1335 | * @param cbMMIO The size of the MMIO memory mapping.
|
---|
| 1336 | * This is optional, pass 0 if not present.
|
---|
| 1337 | * @param enmOSType The guest OS type to report to the VMMDev.
|
---|
| 1338 | * @param fFixedEvents Events that will be enabled upon init and no client
|
---|
| 1339 | * will ever be allowed to mask.
|
---|
| 1340 | */
|
---|
| 1341 | int VGDrvCommonInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase,
|
---|
[100267] | 1342 | void *pvMmioReq, void *pvMMIOBase, uint32_t cbMMIO,
|
---|
| 1343 | VBOXOSTYPE enmOSType, uint32_t fFixedEvents)
|
---|
[70223] | 1344 | {
|
---|
| 1345 | int rc;
|
---|
| 1346 | VGDrvCommonInitLoggers();
|
---|
| 1347 |
|
---|
| 1348 | rc = VGDrvCommonInitDevExtFundament(pDevExt);
|
---|
| 1349 | if (RT_SUCCESS(rc))
|
---|
| 1350 | {
|
---|
[100267] | 1351 | rc = VGDrvCommonInitDevExtResources(pDevExt, IOPortBase, pvMmioReq, pvMMIOBase, cbMMIO,
|
---|
| 1352 | enmOSType, fFixedEvents);
|
---|
[70223] | 1353 | if (RT_SUCCESS(rc))
|
---|
| 1354 | return rc;
|
---|
| 1355 |
|
---|
| 1356 | VGDrvCommonDeleteDevExtFundament(pDevExt);
|
---|
| 1357 | }
|
---|
| 1358 | VGDrvCommonDestroyLoggers();
|
---|
[3657] | 1359 | return rc; /* (failed) */
|
---|
| 1360 | }
|
---|
| 1361 |
|
---|
| 1362 |
|
---|
| 1363 | /**
|
---|
[70066] | 1364 | * Checks if the given option can be taken to not mean 'false'.
|
---|
[70040] | 1365 | *
|
---|
| 1366 | * @returns true or false accordingly.
|
---|
| 1367 | * @param pszValue The value to consider.
|
---|
| 1368 | */
|
---|
| 1369 | bool VBDrvCommonIsOptionValueTrue(const char *pszValue)
|
---|
| 1370 | {
|
---|
| 1371 | if (pszValue)
|
---|
| 1372 | {
|
---|
| 1373 | char ch;
|
---|
| 1374 | while ( (ch = *pszValue) != '\0'
|
---|
| 1375 | && RT_C_IS_SPACE(ch))
|
---|
| 1376 | pszValue++;
|
---|
| 1377 |
|
---|
| 1378 | return ch != '\0'
|
---|
| 1379 | && ch != 'n' /* no */
|
---|
| 1380 | && ch != 'N' /* NO */
|
---|
| 1381 | && ch != 'd' /* disabled */
|
---|
[70066] | 1382 | && ch != 'f' /* false*/
|
---|
| 1383 | && ch != 'F' /* FALSE */
|
---|
[70040] | 1384 | && ch != 'D' /* DISABLED */
|
---|
| 1385 | && ( (ch != 'o' && ch != 'O') /* off, OFF, Off */
|
---|
| 1386 | || (pszValue[1] != 'f' && pszValue[1] != 'F') )
|
---|
| 1387 | && (ch != '0' || pszValue[1] != '\0') /* '0' */
|
---|
| 1388 | ;
|
---|
| 1389 | }
|
---|
| 1390 | return false;
|
---|
| 1391 | }
|
---|
| 1392 |
|
---|
| 1393 |
|
---|
| 1394 | /**
|
---|
| 1395 | * Processes a option.
|
---|
| 1396 | *
|
---|
| 1397 | * This will let the OS specific code have a go at it too.
|
---|
| 1398 | *
|
---|
| 1399 | * @param pDevExt The device extension.
|
---|
| 1400 | * @param pszName The option name, sans prefix.
|
---|
| 1401 | * @param pszValue The option value.
|
---|
| 1402 | */
|
---|
| 1403 | void VGDrvCommonProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue)
|
---|
| 1404 | {
|
---|
[70067] | 1405 | Log(("VGDrvCommonProcessOption: pszName='%s' pszValue='%s'\n", pszName, pszValue));
|
---|
| 1406 |
|
---|
[70095] | 1407 | if ( RTStrICmpAscii(pszName, "r3_log_to_host") == 0
|
---|
| 1408 | || RTStrICmpAscii(pszName, "LoggingEnabled") == 0 /*legacy*/ )
|
---|
[70040] | 1409 | pDevExt->fLoggingEnabled = VBDrvCommonIsOptionValueTrue(pszValue);
|
---|
[70154] | 1410 | else if ( RTStrNICmpAscii(pszName, RT_STR_TUPLE("log")) == 0
|
---|
[70095] | 1411 | || RTStrNICmpAscii(pszName, RT_STR_TUPLE("dbg_log")) == 0)
|
---|
| 1412 | {
|
---|
[79863] | 1413 | bool const fDbgRel = *pszName == 'd' || *pszName == 'D';
|
---|
| 1414 | const char *pszSubName = &pszName[fDbgRel ? 4 + 3 : 3];
|
---|
[70095] | 1415 | if ( !*pszSubName
|
---|
| 1416 | || RTStrICmpAscii(pszSubName, "_flags") == 0
|
---|
| 1417 | || RTStrICmpAscii(pszSubName, "_dest") == 0)
|
---|
| 1418 | {
|
---|
[79863] | 1419 | PRTLOGGER pLogger = !fDbgRel ? RTLogRelGetDefaultInstance() : RTLogDefaultInstance();
|
---|
[70095] | 1420 | if (pLogger)
|
---|
| 1421 | {
|
---|
| 1422 | if (!*pszSubName)
|
---|
| 1423 | RTLogGroupSettings(pLogger, pszValue);
|
---|
| 1424 | else if (RTStrICmpAscii(pszSubName, "_flags"))
|
---|
| 1425 | RTLogFlags(pLogger, pszValue);
|
---|
| 1426 | else
|
---|
| 1427 | RTLogDestinations(pLogger, pszValue);
|
---|
| 1428 | }
|
---|
| 1429 | }
|
---|
| 1430 | else if (!VGDrvNativeProcessOption(pDevExt, pszName, pszValue))
|
---|
| 1431 | LogRel(("VBoxGuest: Ignoring unknown option '%s' (value '%s')\n", pszName, pszValue));
|
---|
| 1432 | }
|
---|
| 1433 | else if (!VGDrvNativeProcessOption(pDevExt, pszName, pszValue))
|
---|
[70040] | 1434 | LogRel(("VBoxGuest: Ignoring unknown option '%s' (value '%s')\n", pszName, pszValue));
|
---|
| 1435 | }
|
---|
| 1436 |
|
---|
| 1437 |
|
---|
| 1438 | /**
|
---|
| 1439 | * Read driver configuration from the host.
|
---|
| 1440 | *
|
---|
| 1441 | * This involves connecting to the guest properties service, which means that
|
---|
| 1442 | * interrupts needs to work and that the calling thread must be able to block.
|
---|
| 1443 | *
|
---|
| 1444 | * @param pDevExt The device extension.
|
---|
| 1445 | */
|
---|
| 1446 | void VGDrvCommonProcessOptionsFromHost(PVBOXGUESTDEVEXT pDevExt)
|
---|
| 1447 | {
|
---|
| 1448 | /*
|
---|
| 1449 | * Create a kernel session without our selves, then connect to the HGCM service.
|
---|
| 1450 | */
|
---|
| 1451 | PVBOXGUESTSESSION pSession;
|
---|
| 1452 | int rc = VGDrvCommonCreateKernelSession(pDevExt, &pSession);
|
---|
| 1453 | if (RT_SUCCESS(rc))
|
---|
| 1454 | {
|
---|
| 1455 | union
|
---|
| 1456 | {
|
---|
| 1457 | VBGLIOCHGCMCONNECT Connect;
|
---|
| 1458 | VBGLIOCHGCMDISCONNECT Disconnect;
|
---|
[70066] | 1459 | GuestPropMsgEnumProperties EnumMsg;
|
---|
[70040] | 1460 | } uBuf;
|
---|
| 1461 |
|
---|
| 1462 | RT_ZERO(uBuf.Connect);
|
---|
| 1463 | VBGLREQHDR_INIT(&uBuf.Connect.Hdr, HGCM_CONNECT);
|
---|
| 1464 | uBuf.Connect.u.In.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
|
---|
| 1465 | RTStrCopy(uBuf.Connect.u.In.Loc.u.host.achName, sizeof(uBuf.Connect.u.In.Loc.u.host.achName),
|
---|
| 1466 | "VBoxGuestPropSvc"); /** @todo Add a define to the header for the name. */
|
---|
| 1467 | rc = VGDrvCommonIoCtl(VBGL_IOCTL_HGCM_CONNECT, pDevExt, pSession, &uBuf.Connect.Hdr, sizeof(uBuf.Connect));
|
---|
| 1468 | if (RT_SUCCESS(rc))
|
---|
| 1469 | {
|
---|
| 1470 | static const char g_szzPattern[] = "/VirtualBox/GuestAdd/VBoxGuest/*\0";
|
---|
| 1471 | uint32_t const idClient = uBuf.Connect.u.Out.idClient;
|
---|
| 1472 | char *pszzStrings = NULL;
|
---|
| 1473 | uint32_t cbStrings;
|
---|
| 1474 |
|
---|
| 1475 | /*
|
---|
[70066] | 1476 | * Enumerate all the relevant properties. We try with a 1KB buffer, but
|
---|
| 1477 | * will double it until we get what we want or go beyond 16KB.
|
---|
[70040] | 1478 | */
|
---|
[70066] | 1479 | for (cbStrings = _1K; cbStrings <= _16K; cbStrings *= 2)
|
---|
[70040] | 1480 | {
|
---|
| 1481 | pszzStrings = (char *)RTMemAllocZ(cbStrings);
|
---|
| 1482 | if (pszzStrings)
|
---|
| 1483 | {
|
---|
[70066] | 1484 | VBGL_HGCM_HDR_INIT(&uBuf.EnumMsg.hdr, idClient, GUEST_PROP_FN_ENUM_PROPS, 3);
|
---|
[70040] | 1485 |
|
---|
| 1486 | uBuf.EnumMsg.patterns.type = VMMDevHGCMParmType_LinAddr;
|
---|
| 1487 | uBuf.EnumMsg.patterns.u.Pointer.size = sizeof(g_szzPattern);
|
---|
| 1488 | uBuf.EnumMsg.patterns.u.Pointer.u.linearAddr = (uintptr_t)g_szzPattern;
|
---|
| 1489 |
|
---|
| 1490 | uBuf.EnumMsg.strings.type = VMMDevHGCMParmType_LinAddr;
|
---|
| 1491 | uBuf.EnumMsg.strings.u.Pointer.size = cbStrings;
|
---|
| 1492 | uBuf.EnumMsg.strings.u.Pointer.u.linearAddr = (uintptr_t)pszzStrings;
|
---|
| 1493 |
|
---|
| 1494 | uBuf.EnumMsg.size.type = VMMDevHGCMParmType_32bit;
|
---|
| 1495 | uBuf.EnumMsg.size.u.value32 = 0;
|
---|
| 1496 |
|
---|
| 1497 | rc = VGDrvCommonIoCtl(VBGL_IOCTL_HGCM_CALL(sizeof(uBuf.EnumMsg)), pDevExt, pSession,
|
---|
| 1498 | &uBuf.EnumMsg.hdr.Hdr, sizeof(uBuf.EnumMsg));
|
---|
| 1499 | if (RT_SUCCESS(rc))
|
---|
[70066] | 1500 | {
|
---|
| 1501 | if ( uBuf.EnumMsg.size.type == VMMDevHGCMParmType_32bit
|
---|
| 1502 | && uBuf.EnumMsg.size.u.value32 <= cbStrings
|
---|
| 1503 | && uBuf.EnumMsg.size.u.value32 > 0)
|
---|
| 1504 | cbStrings = uBuf.EnumMsg.size.u.value32;
|
---|
| 1505 | Log(("VGDrvCommonReadConfigurationFromHost: GUEST_PROP_FN_ENUM_PROPS -> %#x bytes (cbStrings=%#x)\n",
|
---|
| 1506 | uBuf.EnumMsg.size.u.value32, cbStrings));
|
---|
[70040] | 1507 | break;
|
---|
[70066] | 1508 | }
|
---|
[70040] | 1509 |
|
---|
| 1510 | RTMemFree(pszzStrings);
|
---|
| 1511 | pszzStrings = NULL;
|
---|
| 1512 | }
|
---|
| 1513 | else
|
---|
| 1514 | {
|
---|
| 1515 | LogRel(("VGDrvCommonReadConfigurationFromHost: failed to allocate %#x bytes\n", cbStrings));
|
---|
| 1516 | break;
|
---|
| 1517 | }
|
---|
| 1518 | }
|
---|
| 1519 |
|
---|
| 1520 | /*
|
---|
| 1521 | * Disconnect and destroy the session.
|
---|
| 1522 | */
|
---|
| 1523 | VBGLREQHDR_INIT(&uBuf.Disconnect.Hdr, HGCM_DISCONNECT);
|
---|
| 1524 | uBuf.Disconnect.u.In.idClient = idClient;
|
---|
| 1525 | VGDrvCommonIoCtl(VBGL_IOCTL_HGCM_DISCONNECT, pDevExt, pSession, &uBuf.Disconnect.Hdr, sizeof(uBuf.Disconnect));
|
---|
| 1526 |
|
---|
| 1527 | VGDrvCommonCloseSession(pDevExt, pSession);
|
---|
| 1528 |
|
---|
| 1529 | /*
|
---|
| 1530 | * Process the properties if we got any.
|
---|
| 1531 | *
|
---|
| 1532 | * The string buffer contains packed strings in groups of four - name, value,
|
---|
| 1533 | * timestamp (as a decimal string) and flags. It is terminated by four empty
|
---|
| 1534 | * strings. Layout:
|
---|
| 1535 | * Name\0Value\0Timestamp\0Flags\0
|
---|
| 1536 | */
|
---|
| 1537 | if (pszzStrings)
|
---|
| 1538 | {
|
---|
| 1539 | uint32_t off;
|
---|
| 1540 | for (off = 0; off < cbStrings; off++)
|
---|
| 1541 | {
|
---|
| 1542 | /*
|
---|
| 1543 | * Parse the four fields, checking that it's all plain ASCII w/o any control characters.
|
---|
| 1544 | */
|
---|
| 1545 | const char *apszFields[4] = { NULL, NULL, NULL, NULL };
|
---|
| 1546 | bool fValidFields = true;
|
---|
| 1547 | unsigned iField;
|
---|
| 1548 | for (iField = 0; iField < RT_ELEMENTS(apszFields); iField++)
|
---|
| 1549 | {
|
---|
| 1550 | apszFields[0] = &pszzStrings[off];
|
---|
| 1551 | while (off < cbStrings)
|
---|
| 1552 | {
|
---|
| 1553 | char ch = pszzStrings[off++];
|
---|
| 1554 | if ((unsigned)ch < 0x20U || (unsigned)ch > 0x7fU)
|
---|
| 1555 | {
|
---|
| 1556 | if (!ch)
|
---|
| 1557 | break;
|
---|
[70066] | 1558 | if (fValidFields)
|
---|
| 1559 | Log(("VGDrvCommonReadConfigurationFromHost: Invalid char %#x at %#x (field %u)\n",
|
---|
| 1560 | ch, off - 1, iField));
|
---|
[70040] | 1561 | fValidFields = false;
|
---|
| 1562 | }
|
---|
| 1563 | }
|
---|
| 1564 | }
|
---|
[70066] | 1565 | if ( off <= cbStrings
|
---|
[70040] | 1566 | && fValidFields
|
---|
| 1567 | && *apszFields[0] != '\0')
|
---|
| 1568 | {
|
---|
| 1569 | /*
|
---|
| 1570 | * Validate and convert the flags to integer, then process the option.
|
---|
| 1571 | */
|
---|
| 1572 | uint32_t fFlags = 0;
|
---|
[70058] | 1573 | rc = GuestPropValidateFlags(apszFields[3], &fFlags);
|
---|
[70040] | 1574 | if (RT_SUCCESS(rc))
|
---|
| 1575 | {
|
---|
[70058] | 1576 | if (fFlags & GUEST_PROP_F_RDONLYGUEST)
|
---|
[70040] | 1577 | {
|
---|
| 1578 | apszFields[0] += sizeof(g_szzPattern) - 2;
|
---|
| 1579 | VGDrvCommonProcessOption(pDevExt, apszFields[0], apszFields[1]);
|
---|
| 1580 | }
|
---|
| 1581 | else
|
---|
| 1582 | LogRel(("VBoxGuest: Ignoring '%s' as it does not have RDONLYGUEST set\n", apszFields[0]));
|
---|
| 1583 | }
|
---|
| 1584 | else
|
---|
| 1585 | LogRel(("VBoxGuest: Invalid flags '%s' for '%s': %Rrc\n", apszFields[2], apszFields[0], rc));
|
---|
| 1586 | }
|
---|
| 1587 | else if (off < cbStrings)
|
---|
| 1588 | {
|
---|
| 1589 | LogRel(("VBoxGuest: Malformed guest properties enum result!\n"));
|
---|
[70066] | 1590 | Log(("VBoxGuest: off=%#x cbStrings=%#x\n%.*Rhxd\n", off, cbStrings, cbStrings, pszzStrings));
|
---|
[70040] | 1591 | break;
|
---|
| 1592 | }
|
---|
[70066] | 1593 | else if (!fValidFields)
|
---|
[70040] | 1594 | LogRel(("VBoxGuest: Ignoring %.*Rhxs as it has invalid characters in one or more fields\n",
|
---|
| 1595 | (int)strlen(apszFields[0]), apszFields[0]));
|
---|
| 1596 | else
|
---|
| 1597 | break;
|
---|
| 1598 | }
|
---|
| 1599 |
|
---|
| 1600 | RTMemFree(pszzStrings);
|
---|
| 1601 | }
|
---|
| 1602 | else
|
---|
| 1603 | LogRel(("VGDrvCommonReadConfigurationFromHost: failed to enumerate '%s': %Rrc\n", g_szzPattern, rc));
|
---|
| 1604 |
|
---|
| 1605 | }
|
---|
| 1606 | else
|
---|
| 1607 | LogRel(("VGDrvCommonReadConfigurationFromHost: failed to connect: %Rrc\n", rc));
|
---|
| 1608 | }
|
---|
| 1609 | else
|
---|
| 1610 | LogRel(("VGDrvCommonReadConfigurationFromHost: failed to connect: %Rrc\n", rc));
|
---|
| 1611 | }
|
---|
| 1612 |
|
---|
| 1613 |
|
---|
| 1614 | /**
|
---|
[3657] | 1615 | * Destroys the VBoxGuest device extension.
|
---|
[6032] | 1616 | *
|
---|
[75588] | 1617 | * The native code should call this before the driver is unloaded,
|
---|
[3657] | 1618 | * but don't call this on shutdown.
|
---|
[6032] | 1619 | *
|
---|
[3657] | 1620 | * @param pDevExt The device extension.
|
---|
| 1621 | */
|
---|
[58053] | 1622 | void VGDrvCommonDeleteDevExt(PVBOXGUESTDEVEXT pDevExt)
|
---|
[3657] | 1623 | {
|
---|
[58053] | 1624 | Log(("VGDrvCommonDeleteDevExt:\n"));
|
---|
[26632] | 1625 | Log(("VBoxGuest: The additions driver is terminating.\n"));
|
---|
[70223] | 1626 | VGDrvCommonDeleteDevExtResources(pDevExt);
|
---|
| 1627 | VGDrvCommonDeleteDevExtFundament(pDevExt);
|
---|
| 1628 | VGDrvCommonDestroyLoggers();
|
---|
[3657] | 1629 | }
|
---|
| 1630 |
|
---|
| 1631 |
|
---|
| 1632 | /**
|
---|
| 1633 | * Creates a VBoxGuest user session.
|
---|
[6032] | 1634 | *
|
---|
| 1635 | * The native code calls this when a ring-3 client opens the device.
|
---|
[58053] | 1636 | * Use VGDrvCommonCreateKernelSession when a ring-0 client connects.
|
---|
[6032] | 1637 | *
|
---|
[3657] | 1638 | * @returns VBox status code.
|
---|
| 1639 | * @param pDevExt The device extension.
|
---|
[70873] | 1640 | * @param fRequestor VMMDEV_REQUESTOR_XXX.
|
---|
[3657] | 1641 | * @param ppSession Where to store the session on success.
|
---|
| 1642 | */
|
---|
[70873] | 1643 | int VGDrvCommonCreateUserSession(PVBOXGUESTDEVEXT pDevExt, uint32_t fRequestor, PVBOXGUESTSESSION *ppSession)
|
---|
[3657] | 1644 | {
|
---|
| 1645 | PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)RTMemAllocZ(sizeof(*pSession));
|
---|
| 1646 | if (RT_UNLIKELY(!pSession))
|
---|
| 1647 | {
|
---|
[58053] | 1648 | LogRel(("VGDrvCommonCreateUserSession: no memory!\n"));
|
---|
[3657] | 1649 | return VERR_NO_MEMORY;
|
---|
| 1650 | }
|
---|
| 1651 |
|
---|
| 1652 | pSession->Process = RTProcSelf();
|
---|
| 1653 | pSession->R0Process = RTR0ProcHandleSelf();
|
---|
| 1654 | pSession->pDevExt = pDevExt;
|
---|
[70873] | 1655 | pSession->fRequestor = fRequestor;
|
---|
| 1656 | pSession->fUserSession = RT_BOOL(fRequestor & VMMDEV_REQUESTOR_USER_DEVICE);
|
---|
[50523] | 1657 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
| 1658 | RTListAppend(&pDevExt->SessionList, &pSession->ListNode);
|
---|
[54601] | 1659 | pDevExt->cSessions++;
|
---|
[52618] | 1660 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
[3657] | 1661 |
|
---|
| 1662 | *ppSession = pSession;
|
---|
[58053] | 1663 | LogFlow(("VGDrvCommonCreateUserSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
|
---|
[3657] | 1664 | pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
|
---|
| 1665 | return VINF_SUCCESS;
|
---|
| 1666 | }
|
---|
| 1667 |
|
---|
| 1668 |
|
---|
| 1669 | /**
|
---|
| 1670 | * Creates a VBoxGuest kernel session.
|
---|
[6032] | 1671 | *
|
---|
| 1672 | * The native code calls this when a ring-0 client connects to the device.
|
---|
[58053] | 1673 | * Use VGDrvCommonCreateUserSession when a ring-3 client opens the device.
|
---|
[6032] | 1674 | *
|
---|
[3657] | 1675 | * @returns VBox status code.
|
---|
| 1676 | * @param pDevExt The device extension.
|
---|
| 1677 | * @param ppSession Where to store the session on success.
|
---|
| 1678 | */
|
---|
[58053] | 1679 | int VGDrvCommonCreateKernelSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *ppSession)
|
---|
[3657] | 1680 | {
|
---|
| 1681 | PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)RTMemAllocZ(sizeof(*pSession));
|
---|
| 1682 | if (RT_UNLIKELY(!pSession))
|
---|
| 1683 | {
|
---|
[58053] | 1684 | LogRel(("VGDrvCommonCreateKernelSession: no memory!\n"));
|
---|
[3657] | 1685 | return VERR_NO_MEMORY;
|
---|
| 1686 | }
|
---|
| 1687 |
|
---|
| 1688 | pSession->Process = NIL_RTPROCESS;
|
---|
| 1689 | pSession->R0Process = NIL_RTR0PROCESS;
|
---|
| 1690 | pSession->pDevExt = pDevExt;
|
---|
[70873] | 1691 | pSession->fRequestor = VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER
|
---|
| 1692 | | VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
|
---|
[50523] | 1693 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
| 1694 | RTListAppend(&pDevExt->SessionList, &pSession->ListNode);
|
---|
[54601] | 1695 | pDevExt->cSessions++;
|
---|
[52618] | 1696 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
[3657] | 1697 |
|
---|
| 1698 | *ppSession = pSession;
|
---|
[58053] | 1699 | LogFlow(("VGDrvCommonCreateKernelSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
|
---|
[54237] | 1700 | pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
|
---|
[3657] | 1701 | return VINF_SUCCESS;
|
---|
| 1702 | }
|
---|
| 1703 |
|
---|
| 1704 |
|
---|
| 1705 | /**
|
---|
| 1706 | * Closes a VBoxGuest session.
|
---|
[6032] | 1707 | *
|
---|
[3657] | 1708 | * @param pDevExt The device extension.
|
---|
| 1709 | * @param pSession The session to close (and free).
|
---|
| 1710 | */
|
---|
[58053] | 1711 | void VGDrvCommonCloseSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
|
---|
[3657] | 1712 | {
|
---|
[54522] | 1713 | #ifdef VBOX_WITH_HGCM
|
---|
| 1714 | unsigned i;
|
---|
| 1715 | #endif
|
---|
[58053] | 1716 | LogFlow(("VGDrvCommonCloseSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
|
---|
[54239] | 1717 | pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
|
---|
[3657] | 1718 |
|
---|
[50523] | 1719 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
| 1720 | RTListNodeRemove(&pSession->ListNode);
|
---|
[54601] | 1721 | pDevExt->cSessions--;
|
---|
[52618] | 1722 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
[68550] | 1723 | vgdrvAcquireSessionCapabilities(pDevExt, pSession, 0, UINT32_MAX, VBGL_IOC_AGC_FLAGS_DEFAULT, true /*fSessionTermination*/);
|
---|
| 1724 | vgdrvSetSessionCapabilities(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/,
|
---|
| 1725 | NULL /*pfSessionCaps*/, NULL /*pfGlobalCaps*/, true /*fSessionTermination*/);
|
---|
[58053] | 1726 | vgdrvSetSessionEventFilter(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
|
---|
| 1727 | vgdrvSetSessionMouseStatus(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
|
---|
[45760] | 1728 |
|
---|
[58053] | 1729 | vgdrvIoCtl_CancelAllWaitEvents(pDevExt, pSession);
|
---|
[45811] | 1730 |
|
---|
[11820] | 1731 | #ifdef VBOX_WITH_HGCM
|
---|
[21118] | 1732 | for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
|
---|
[3657] | 1733 | if (pSession->aHGCMClientIds[i])
|
---|
| 1734 | {
|
---|
[68550] | 1735 | uint32_t idClient = pSession->aHGCMClientIds[i];
|
---|
[3657] | 1736 | pSession->aHGCMClientIds[i] = 0;
|
---|
[68550] | 1737 | Log(("VGDrvCommonCloseSession: disconnecting client id %#RX32\n", idClient));
|
---|
[70873] | 1738 | VbglR0HGCMInternalDisconnect(idClient, VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV,
|
---|
| 1739 | vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
|
---|
[3657] | 1740 | }
|
---|
[6032] | 1741 | #endif
|
---|
[3657] | 1742 |
|
---|
| 1743 | pSession->pDevExt = NULL;
|
---|
| 1744 | pSession->Process = NIL_RTPROCESS;
|
---|
| 1745 | pSession->R0Process = NIL_RTR0PROCESS;
|
---|
[58053] | 1746 | vgdrvCloseMemBalloon(pDevExt, pSession);
|
---|
[50623] | 1747 | RTMemFree(pSession);
|
---|
[3657] | 1748 | }
|
---|
| 1749 |
|
---|
| 1750 |
|
---|
| 1751 | /**
|
---|
[32449] | 1752 | * Allocates a wait-for-event entry.
|
---|
[6032] | 1753 | *
|
---|
[3657] | 1754 | * @returns The wait-for-event entry.
|
---|
| 1755 | * @param pDevExt The device extension.
|
---|
[21491] | 1756 | * @param pSession The session that's allocating this. Can be NULL.
|
---|
[3657] | 1757 | */
|
---|
[58053] | 1758 | static PVBOXGUESTWAIT vgdrvWaitAlloc(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
|
---|
[3657] | 1759 | {
|
---|
[6032] | 1760 | /*
|
---|
| 1761 | * Allocate it one way or the other.
|
---|
[3657] | 1762 | */
|
---|
[34406] | 1763 | PVBOXGUESTWAIT pWait = RTListGetFirst(&pDevExt->FreeList, VBOXGUESTWAIT, ListNode);
|
---|
[3657] | 1764 | if (pWait)
|
---|
| 1765 | {
|
---|
[40806] | 1766 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[3657] | 1767 |
|
---|
[34406] | 1768 | pWait = RTListGetFirst(&pDevExt->FreeList, VBOXGUESTWAIT, ListNode);
|
---|
[3657] | 1769 | if (pWait)
|
---|
[32449] | 1770 | RTListNodeRemove(&pWait->ListNode);
|
---|
[3657] | 1771 |
|
---|
[52618] | 1772 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[3657] | 1773 | }
|
---|
| 1774 | if (!pWait)
|
---|
| 1775 | {
|
---|
[21118] | 1776 | int rc;
|
---|
[3657] | 1777 |
|
---|
| 1778 | pWait = (PVBOXGUESTWAIT)RTMemAlloc(sizeof(*pWait));
|
---|
| 1779 | if (!pWait)
|
---|
| 1780 | {
|
---|
[58053] | 1781 | LogRelMax(32, ("vgdrvWaitAlloc: out-of-memory!\n"));
|
---|
[3657] | 1782 | return NULL;
|
---|
| 1783 | }
|
---|
| 1784 |
|
---|
[21118] | 1785 | rc = RTSemEventMultiCreate(&pWait->Event);
|
---|
[3657] | 1786 | if (RT_FAILURE(rc))
|
---|
| 1787 | {
|
---|
[58053] | 1788 | LogRelMax(32, ("vgdrvWaitAlloc: RTSemEventMultiCreate failed with rc=%Rrc!\n", rc));
|
---|
[3657] | 1789 | RTMemFree(pWait);
|
---|
| 1790 | return NULL;
|
---|
| 1791 | }
|
---|
[32449] | 1792 |
|
---|
| 1793 | pWait->ListNode.pNext = NULL;
|
---|
| 1794 | pWait->ListNode.pPrev = NULL;
|
---|
[3657] | 1795 | }
|
---|
| 1796 |
|
---|
[6032] | 1797 | /*
|
---|
[3657] | 1798 | * Zero members just as an precaution.
|
---|
| 1799 | */
|
---|
| 1800 | pWait->fReqEvents = 0;
|
---|
| 1801 | pWait->fResEvents = 0;
|
---|
[32449] | 1802 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
| 1803 | pWait->fPendingWakeUp = false;
|
---|
| 1804 | pWait->fFreeMe = false;
|
---|
| 1805 | #endif
|
---|
[21491] | 1806 | pWait->pSession = pSession;
|
---|
[11820] | 1807 | #ifdef VBOX_WITH_HGCM
|
---|
[3657] | 1808 | pWait->pHGCMReq = NULL;
|
---|
| 1809 | #endif
|
---|
| 1810 | RTSemEventMultiReset(pWait->Event);
|
---|
| 1811 | return pWait;
|
---|
| 1812 | }
|
---|
| 1813 |
|
---|
| 1814 |
|
---|
| 1815 | /**
|
---|
| 1816 | * Frees the wait-for-event entry.
|
---|
[6032] | 1817 | *
|
---|
[32449] | 1818 | * The caller must own the wait spinlock !
|
---|
| 1819 | * The entry must be in a list!
|
---|
| 1820 | *
|
---|
[3657] | 1821 | * @param pDevExt The device extension.
|
---|
| 1822 | * @param pWait The wait-for-event entry to free.
|
---|
| 1823 | */
|
---|
[58053] | 1824 | static void vgdrvWaitFreeLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTWAIT pWait)
|
---|
[3657] | 1825 | {
|
---|
| 1826 | pWait->fReqEvents = 0;
|
---|
| 1827 | pWait->fResEvents = 0;
|
---|
[11820] | 1828 | #ifdef VBOX_WITH_HGCM
|
---|
[3657] | 1829 | pWait->pHGCMReq = NULL;
|
---|
| 1830 | #endif
|
---|
[32449] | 1831 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
| 1832 | Assert(!pWait->fFreeMe);
|
---|
| 1833 | if (pWait->fPendingWakeUp)
|
---|
| 1834 | pWait->fFreeMe = true;
|
---|
| 1835 | else
|
---|
| 1836 | #endif
|
---|
| 1837 | {
|
---|
| 1838 | RTListNodeRemove(&pWait->ListNode);
|
---|
| 1839 | RTListAppend(&pDevExt->FreeList, &pWait->ListNode);
|
---|
| 1840 | }
|
---|
[3657] | 1841 | }
|
---|
| 1842 |
|
---|
| 1843 |
|
---|
| 1844 | /**
|
---|
| 1845 | * Frees the wait-for-event entry.
|
---|
[6032] | 1846 | *
|
---|
[3657] | 1847 | * @param pDevExt The device extension.
|
---|
| 1848 | * @param pWait The wait-for-event entry to free.
|
---|
| 1849 | */
|
---|
[58053] | 1850 | static void vgdrvWaitFreeUnlocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTWAIT pWait)
|
---|
[3657] | 1851 | {
|
---|
[40806] | 1852 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[58053] | 1853 | vgdrvWaitFreeLocked(pDevExt, pWait);
|
---|
[52618] | 1854 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[3657] | 1855 | }
|
---|
| 1856 |
|
---|
| 1857 |
|
---|
[32449] | 1858 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
[8328] | 1859 | /**
|
---|
[32449] | 1860 | * Processes the wake-up list.
|
---|
| 1861 | *
|
---|
| 1862 | * All entries in the wake-up list gets signalled and moved to the woken-up
|
---|
| 1863 | * list.
|
---|
[63948] | 1864 | * At least on Windows this function can be invoked concurrently from
|
---|
| 1865 | * different VCPUs. So, be thread-safe.
|
---|
[32449] | 1866 | *
|
---|
| 1867 | * @param pDevExt The device extension.
|
---|
| 1868 | */
|
---|
[58053] | 1869 | void VGDrvCommonWaitDoWakeUps(PVBOXGUESTDEVEXT pDevExt)
|
---|
[32449] | 1870 | {
|
---|
| 1871 | if (!RTListIsEmpty(&pDevExt->WakeUpList))
|
---|
| 1872 | {
|
---|
[40806] | 1873 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[32449] | 1874 | for (;;)
|
---|
| 1875 | {
|
---|
| 1876 | int rc;
|
---|
[34406] | 1877 | PVBOXGUESTWAIT pWait = RTListGetFirst(&pDevExt->WakeUpList, VBOXGUESTWAIT, ListNode);
|
---|
[32449] | 1878 | if (!pWait)
|
---|
| 1879 | break;
|
---|
[63948] | 1880 | /* Prevent other threads from accessing pWait when spinlock is released. */
|
---|
| 1881 | RTListNodeRemove(&pWait->ListNode);
|
---|
| 1882 |
|
---|
[32449] | 1883 | pWait->fPendingWakeUp = true;
|
---|
[52618] | 1884 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[32449] | 1885 |
|
---|
| 1886 | rc = RTSemEventMultiSignal(pWait->Event);
|
---|
| 1887 | AssertRC(rc);
|
---|
| 1888 |
|
---|
[40806] | 1889 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[63948] | 1890 | Assert(pWait->ListNode.pNext == NULL && pWait->ListNode.pPrev == NULL);
|
---|
| 1891 | RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
|
---|
[32449] | 1892 | pWait->fPendingWakeUp = false;
|
---|
[63948] | 1893 | if (RT_LIKELY(!pWait->fFreeMe))
|
---|
| 1894 | { /* likely */ }
|
---|
[32449] | 1895 | else
|
---|
| 1896 | {
|
---|
| 1897 | pWait->fFreeMe = false;
|
---|
[58053] | 1898 | vgdrvWaitFreeLocked(pDevExt, pWait);
|
---|
[32449] | 1899 | }
|
---|
| 1900 | }
|
---|
[52618] | 1901 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[32449] | 1902 | }
|
---|
| 1903 | }
|
---|
| 1904 | #endif /* VBOXGUEST_USE_DEFERRED_WAKE_UP */
|
---|
| 1905 |
|
---|
| 1906 |
|
---|
| 1907 | /**
|
---|
[3657] | 1908 | * Implements the fast (no input or output) type of IOCtls.
|
---|
[6032] | 1909 | *
|
---|
[3657] | 1910 | * This is currently just a placeholder stub inherited from the support driver code.
|
---|
[6032] | 1911 | *
|
---|
[3657] | 1912 | * @returns VBox status code.
|
---|
| 1913 | * @param iFunction The IOCtl function number.
|
---|
| 1914 | * @param pDevExt The device extension.
|
---|
| 1915 | * @param pSession The session.
|
---|
| 1916 | */
|
---|
[68561] | 1917 | int VGDrvCommonIoCtlFast(uintptr_t iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
|
---|
[3657] | 1918 | {
|
---|
[58053] | 1919 | LogFlow(("VGDrvCommonIoCtlFast: iFunction=%#x pDevExt=%p pSession=%p\n", iFunction, pDevExt, pSession));
|
---|
[3657] | 1920 |
|
---|
[27023] | 1921 | NOREF(iFunction);
|
---|
| 1922 | NOREF(pDevExt);
|
---|
| 1923 | NOREF(pSession);
|
---|
[3657] | 1924 | return VERR_NOT_SUPPORTED;
|
---|
| 1925 | }
|
---|
| 1926 |
|
---|
| 1927 |
|
---|
[27023] | 1928 | /**
|
---|
[68550] | 1929 | * Gets the driver I/O control interface version, maybe adjusting it for
|
---|
| 1930 | * backwards compatibility.
|
---|
[27023] | 1931 | *
|
---|
[68550] | 1932 | * The adjusting is currently not implemented as we only have one major I/O
|
---|
| 1933 | * control interface version out there to support. This is something we will
|
---|
| 1934 | * implement as needed.
|
---|
| 1935 | *
|
---|
[27023] | 1936 | * returns IPRT status code.
|
---|
| 1937 | * @param pDevExt The device extension.
|
---|
[68550] | 1938 | * @param pSession The session.
|
---|
| 1939 | * @param pReq The request info.
|
---|
| 1940 | */
|
---|
| 1941 | static int vgdrvIoCtl_DriverVersionInfo(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCDRIVERVERSIONINFO pReq)
|
---|
| 1942 | {
|
---|
| 1943 | int rc;
|
---|
| 1944 | LogFlow(("VBGL_IOCTL_DRIVER_VERSION_INFO: uReqVersion=%#x uMinVersion=%#x uReserved1=%#x uReserved2=%#x\n",
|
---|
| 1945 | pReq->u.In.uReqVersion, pReq->u.In.uMinVersion, pReq->u.In.uReserved1, pReq->u.In.uReserved2));
|
---|
| 1946 | RT_NOREF2(pDevExt, pSession);
|
---|
| 1947 |
|
---|
| 1948 | /*
|
---|
| 1949 | * Input validation.
|
---|
| 1950 | */
|
---|
| 1951 | if ( pReq->u.In.uMinVersion <= pReq->u.In.uReqVersion
|
---|
| 1952 | && RT_HI_U16(pReq->u.In.uMinVersion) == RT_HI_U16(pReq->u.In.uReqVersion))
|
---|
| 1953 | {
|
---|
| 1954 | /*
|
---|
| 1955 | * Match the version.
|
---|
| 1956 | * The current logic is very simple, match the major interface version.
|
---|
| 1957 | */
|
---|
| 1958 | if ( pReq->u.In.uMinVersion <= VBGL_IOC_VERSION
|
---|
| 1959 | && RT_HI_U16(pReq->u.In.uMinVersion) == RT_HI_U16(VBGL_IOC_VERSION))
|
---|
| 1960 | rc = VINF_SUCCESS;
|
---|
| 1961 | else
|
---|
| 1962 | {
|
---|
[68558] | 1963 | LogRel(("VBGL_IOCTL_DRIVER_VERSION_INFO: Version mismatch. Requested: %#x Min: %#x Current: %#x\n",
|
---|
[68550] | 1964 | pReq->u.In.uReqVersion, pReq->u.In.uMinVersion, VBGL_IOC_VERSION));
|
---|
| 1965 | rc = VERR_VERSION_MISMATCH;
|
---|
| 1966 | }
|
---|
| 1967 | }
|
---|
| 1968 | else
|
---|
| 1969 | {
|
---|
[68558] | 1970 | LogRel(("VBGL_IOCTL_DRIVER_VERSION_INFO: uMinVersion=%#x uMaxVersion=%#x doesn't match!\n",
|
---|
[68550] | 1971 | pReq->u.In.uMinVersion, pReq->u.In.uReqVersion));
|
---|
| 1972 | rc = VERR_INVALID_PARAMETER;
|
---|
| 1973 | }
|
---|
| 1974 |
|
---|
| 1975 | pReq->u.Out.uSessionVersion = RT_SUCCESS(rc) ? VBGL_IOC_VERSION : UINT32_MAX;
|
---|
| 1976 | pReq->u.Out.uDriverVersion = VBGL_IOC_VERSION;
|
---|
| 1977 | pReq->u.Out.uDriverRevision = VBOX_SVN_REV;
|
---|
| 1978 | pReq->u.Out.uReserved1 = 0;
|
---|
| 1979 | pReq->u.Out.uReserved2 = 0;
|
---|
| 1980 | return rc;
|
---|
| 1981 | }
|
---|
| 1982 |
|
---|
| 1983 |
|
---|
| 1984 | /**
|
---|
| 1985 | * Similar to vgdrvIoCtl_DriverVersionInfo, except its for IDC.
|
---|
| 1986 | *
|
---|
| 1987 | * returns IPRT status code.
|
---|
| 1988 | * @param pDevExt The device extension.
|
---|
| 1989 | * @param pSession The session.
|
---|
| 1990 | * @param pReq The request info.
|
---|
| 1991 | */
|
---|
| 1992 | static int vgdrvIoCtl_IdcConnect(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCIDCCONNECT pReq)
|
---|
| 1993 | {
|
---|
| 1994 | int rc;
|
---|
| 1995 | LogFlow(("VBGL_IOCTL_IDC_CONNECT: u32MagicCookie=%#x uReqVersion=%#x uMinVersion=%#x uReserved=%#x\n",
|
---|
| 1996 | pReq->u.In.u32MagicCookie, pReq->u.In.uReqVersion, pReq->u.In.uMinVersion, pReq->u.In.uReserved));
|
---|
| 1997 | Assert(pSession != NULL);
|
---|
| 1998 | RT_NOREF(pDevExt);
|
---|
| 1999 |
|
---|
| 2000 | /*
|
---|
| 2001 | * Input validation.
|
---|
| 2002 | */
|
---|
| 2003 | if (pReq->u.In.u32MagicCookie == VBGL_IOCTL_IDC_CONNECT_MAGIC_COOKIE)
|
---|
| 2004 | {
|
---|
| 2005 | if ( pReq->u.In.uMinVersion <= pReq->u.In.uReqVersion
|
---|
| 2006 | && RT_HI_U16(pReq->u.In.uMinVersion) == RT_HI_U16(pReq->u.In.uReqVersion))
|
---|
| 2007 | {
|
---|
| 2008 | /*
|
---|
| 2009 | * Match the version.
|
---|
| 2010 | * The current logic is very simple, match the major interface version.
|
---|
| 2011 | */
|
---|
| 2012 | if ( pReq->u.In.uMinVersion <= VBGL_IOC_VERSION
|
---|
| 2013 | && RT_HI_U16(pReq->u.In.uMinVersion) == RT_HI_U16(VBGL_IOC_VERSION))
|
---|
| 2014 | {
|
---|
| 2015 | pReq->u.Out.pvSession = pSession;
|
---|
| 2016 | pReq->u.Out.uSessionVersion = VBGL_IOC_VERSION;
|
---|
| 2017 | pReq->u.Out.uDriverVersion = VBGL_IOC_VERSION;
|
---|
| 2018 | pReq->u.Out.uDriverRevision = VBOX_SVN_REV;
|
---|
| 2019 | pReq->u.Out.uReserved1 = 0;
|
---|
| 2020 | pReq->u.Out.pvReserved2 = NULL;
|
---|
| 2021 | return VINF_SUCCESS;
|
---|
| 2022 |
|
---|
| 2023 | }
|
---|
| 2024 | LogRel(("VBGL_IOCTL_IDC_CONNECT: Version mismatch. Requested: %#x Min: %#x Current: %#x\n",
|
---|
| 2025 | pReq->u.In.uReqVersion, pReq->u.In.uMinVersion, VBGL_IOC_VERSION));
|
---|
| 2026 | rc = VERR_VERSION_MISMATCH;
|
---|
| 2027 | }
|
---|
| 2028 | else
|
---|
| 2029 | {
|
---|
| 2030 | LogRel(("VBGL_IOCTL_IDC_CONNECT: uMinVersion=%#x uMaxVersion=%#x doesn't match!\n",
|
---|
| 2031 | pReq->u.In.uMinVersion, pReq->u.In.uReqVersion));
|
---|
| 2032 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2033 | }
|
---|
| 2034 |
|
---|
| 2035 | pReq->u.Out.pvSession = NULL;
|
---|
| 2036 | pReq->u.Out.uSessionVersion = UINT32_MAX;
|
---|
| 2037 | pReq->u.Out.uDriverVersion = VBGL_IOC_VERSION;
|
---|
| 2038 | pReq->u.Out.uDriverRevision = VBOX_SVN_REV;
|
---|
| 2039 | pReq->u.Out.uReserved1 = 0;
|
---|
| 2040 | pReq->u.Out.pvReserved2 = NULL;
|
---|
| 2041 | }
|
---|
| 2042 | else
|
---|
| 2043 | {
|
---|
| 2044 | LogRel(("VBGL_IOCTL_IDC_CONNECT: u32MagicCookie=%#x expected %#x!\n",
|
---|
| 2045 | pReq->u.In.u32MagicCookie, VBGL_IOCTL_IDC_CONNECT_MAGIC_COOKIE));
|
---|
| 2046 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2047 | }
|
---|
| 2048 | return rc;
|
---|
| 2049 | }
|
---|
| 2050 |
|
---|
| 2051 |
|
---|
| 2052 | /**
|
---|
| 2053 | * Counterpart to vgdrvIoCtl_IdcConnect, destroys the session.
|
---|
| 2054 | *
|
---|
| 2055 | * returns IPRT status code.
|
---|
| 2056 | * @param pDevExt The device extension.
|
---|
| 2057 | * @param pSession The session.
|
---|
| 2058 | * @param pReq The request info.
|
---|
| 2059 | */
|
---|
| 2060 | static int vgdrvIoCtl_IdcDisconnect(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCIDCDISCONNECT pReq)
|
---|
| 2061 | {
|
---|
| 2062 | LogFlow(("VBGL_IOCTL_IDC_DISCONNECT: pvSession=%p vs pSession=%p\n", pReq->u.In.pvSession, pSession));
|
---|
| 2063 | RT_NOREF(pDevExt);
|
---|
| 2064 | Assert(pSession != NULL);
|
---|
| 2065 |
|
---|
| 2066 | if (pReq->u.In.pvSession == pSession)
|
---|
| 2067 | {
|
---|
| 2068 | VGDrvCommonCloseSession(pDevExt, pSession);
|
---|
| 2069 | return VINF_SUCCESS;
|
---|
| 2070 | }
|
---|
| 2071 | LogRel(("VBGL_IOCTL_IDC_DISCONNECT: In.pvSession=%p is not equal to pSession=%p!\n", pReq->u.In.pvSession, pSession));
|
---|
| 2072 | return VERR_INVALID_PARAMETER;
|
---|
| 2073 | }
|
---|
| 2074 |
|
---|
| 2075 |
|
---|
| 2076 | /**
|
---|
| 2077 | * Return the VMM device I/O info.
|
---|
| 2078 | *
|
---|
| 2079 | * returns IPRT status code.
|
---|
| 2080 | * @param pDevExt The device extension.
|
---|
[27023] | 2081 | * @param pInfo The request info.
|
---|
[68550] | 2082 | * @note Ring-0 only, caller checked.
|
---|
[27023] | 2083 | */
|
---|
[68550] | 2084 | static int vgdrvIoCtl_GetVMMDevIoInfo(PVBOXGUESTDEVEXT pDevExt, PVBGLIOCGETVMMDEVIOINFO pInfo)
|
---|
[3657] | 2085 | {
|
---|
[68550] | 2086 | LogFlow(("VBGL_IOCTL_GET_VMMDEV_IO_INFO\n"));
|
---|
[50803] | 2087 |
|
---|
[68550] | 2088 | pInfo->u.Out.IoPort = pDevExt->IOPortBase;
|
---|
| 2089 | pInfo->u.Out.pvVmmDevMapping = pDevExt->pVMMDevMemory;
|
---|
[100267] | 2090 | pInfo->u.Out.pMmioReq = pDevExt->pMmioReq;
|
---|
[68550] | 2091 | pInfo->u.Out.auPadding[0] = 0;
|
---|
| 2092 | #if HC_ARCH_BITS != 32
|
---|
| 2093 | pInfo->u.Out.auPadding[1] = 0;
|
---|
| 2094 | pInfo->u.Out.auPadding[2] = 0;
|
---|
| 2095 | #endif
|
---|
[3657] | 2096 | return VINF_SUCCESS;
|
---|
| 2097 | }
|
---|
| 2098 |
|
---|
| 2099 |
|
---|
| 2100 | /**
|
---|
[41640] | 2101 | * Set the callback for the kernel mouse handler.
|
---|
| 2102 | *
|
---|
| 2103 | * returns IPRT status code.
|
---|
| 2104 | * @param pDevExt The device extension.
|
---|
| 2105 | * @param pNotify The new callback information.
|
---|
| 2106 | */
|
---|
[77728] | 2107 | static int vgdrvIoCtl_SetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, PVBGLIOCSETMOUSENOTIFYCALLBACK pNotify)
|
---|
[41640] | 2108 | {
|
---|
[68550] | 2109 | LogFlow(("VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK: pfnNotify=%p pvUser=%p\n", pNotify->u.In.pfnNotify, pNotify->u.In.pvUser));
|
---|
[41642] | 2110 |
|
---|
[64435] | 2111 | #ifdef VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
|
---|
| 2112 | VGDrvNativeSetMouseNotifyCallback(pDevExt, pNotify);
|
---|
| 2113 | #else
|
---|
[41642] | 2114 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[68550] | 2115 | pDevExt->pfnMouseNotifyCallback = pNotify->u.In.pfnNotify;
|
---|
| 2116 | pDevExt->pvMouseNotifyCallbackArg = pNotify->u.In.pvUser;
|
---|
[52618] | 2117 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[64435] | 2118 | #endif
|
---|
[41640] | 2119 | return VINF_SUCCESS;
|
---|
| 2120 | }
|
---|
| 2121 |
|
---|
| 2122 |
|
---|
| 2123 | /**
|
---|
[58053] | 2124 | * Worker vgdrvIoCtl_WaitEvent.
|
---|
[6032] | 2125 | *
|
---|
[32449] | 2126 | * The caller enters the spinlock, we leave it.
|
---|
| 2127 | *
|
---|
[3657] | 2128 | * @returns VINF_SUCCESS if we've left the spinlock and can return immediately.
|
---|
| 2129 | */
|
---|
[54608] | 2130 | DECLINLINE(int) vbdgCheckWaitEventCondition(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
[68550] | 2131 | PVBGLIOCWAITFOREVENTS pInfo, int iEvent, const uint32_t fReqEvents)
|
---|
[3657] | 2132 | {
|
---|
[54601] | 2133 | uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents;
|
---|
| 2134 | if (fMatches & VBOXGUEST_ACQUIRE_STYLE_EVENTS)
|
---|
[58053] | 2135 | fMatches &= vgdrvGetAllowedEventMaskForSession(pDevExt, pSession);
|
---|
[50372] | 2136 | if (fMatches || pSession->fPendingCancelWaitEvents)
|
---|
[3657] | 2137 | {
|
---|
[54601] | 2138 | ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches);
|
---|
[52618] | 2139 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[3657] | 2140 |
|
---|
[68550] | 2141 | pInfo->u.Out.fEvents = fMatches;
|
---|
[3657] | 2142 | if (fReqEvents & ~((uint32_t)1 << iEvent))
|
---|
[68550] | 2143 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x\n", pInfo->u.Out.fEvents));
|
---|
[3657] | 2144 | else
|
---|
[68550] | 2145 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x/%d\n", pInfo->u.Out.fEvents, iEvent));
|
---|
[50372] | 2146 | pSession->fPendingCancelWaitEvents = false;
|
---|
[3657] | 2147 | return VINF_SUCCESS;
|
---|
| 2148 | }
|
---|
[50803] | 2149 |
|
---|
[52618] | 2150 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[3657] | 2151 | return VERR_TIMEOUT;
|
---|
| 2152 | }
|
---|
| 2153 |
|
---|
| 2154 |
|
---|
[68550] | 2155 | static int vgdrvIoCtl_WaitForEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
| 2156 | PVBGLIOCWAITFOREVENTS pInfo, bool fInterruptible)
|
---|
[3657] | 2157 | {
|
---|
[68550] | 2158 | uint32_t const cMsTimeout = pInfo->u.In.cMsTimeOut;
|
---|
| 2159 | const uint32_t fReqEvents = pInfo->u.In.fEvents;
|
---|
[31752] | 2160 | uint32_t fResEvents;
|
---|
| 2161 | int iEvent;
|
---|
| 2162 | PVBOXGUESTWAIT pWait;
|
---|
| 2163 | int rc;
|
---|
[31720] | 2164 |
|
---|
[68550] | 2165 | pInfo->u.Out.fEvents = 0; /* Note! This overwrites pInfo->u.In.* fields! */
|
---|
[3657] | 2166 |
|
---|
| 2167 | /*
|
---|
[6032] | 2168 | * Copy and verify the input mask.
|
---|
[3657] | 2169 | */
|
---|
[31720] | 2170 | iEvent = ASMBitFirstSetU32(fReqEvents) - 1;
|
---|
[3657] | 2171 | if (RT_UNLIKELY(iEvent < 0))
|
---|
| 2172 | {
|
---|
[54615] | 2173 | LogRel(("VBOXGUEST_IOCTL_WAITEVENT: Invalid input mask %#x!!\n", fReqEvents));
|
---|
[3657] | 2174 | return VERR_INVALID_PARAMETER;
|
---|
| 2175 | }
|
---|
| 2176 |
|
---|
| 2177 | /*
|
---|
| 2178 | * Check the condition up front, before doing the wait-for-event allocations.
|
---|
| 2179 | */
|
---|
[40806] | 2180 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[54608] | 2181 | rc = vbdgCheckWaitEventCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents);
|
---|
[3657] | 2182 | if (rc == VINF_SUCCESS)
|
---|
| 2183 | return rc;
|
---|
| 2184 |
|
---|
[68550] | 2185 | if (!cMsTimeout)
|
---|
[3657] | 2186 | {
|
---|
[54615] | 2187 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_TIMEOUT\n"));
|
---|
[3657] | 2188 | return VERR_TIMEOUT;
|
---|
| 2189 | }
|
---|
| 2190 |
|
---|
[58053] | 2191 | pWait = vgdrvWaitAlloc(pDevExt, pSession);
|
---|
[3657] | 2192 | if (!pWait)
|
---|
| 2193 | return VERR_NO_MEMORY;
|
---|
| 2194 | pWait->fReqEvents = fReqEvents;
|
---|
| 2195 |
|
---|
| 2196 | /*
|
---|
| 2197 | * We've got the wait entry now, re-enter the spinlock and check for the condition.
|
---|
[6032] | 2198 | * If the wait condition is met, return.
|
---|
[3657] | 2199 | * Otherwise enter into the list and go to sleep waiting for the ISR to signal us.
|
---|
| 2200 | */
|
---|
[40806] | 2201 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[32449] | 2202 | RTListAppend(&pDevExt->WaitList, &pWait->ListNode);
|
---|
[54608] | 2203 | rc = vbdgCheckWaitEventCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents);
|
---|
[3657] | 2204 | if (rc == VINF_SUCCESS)
|
---|
| 2205 | {
|
---|
[58053] | 2206 | vgdrvWaitFreeUnlocked(pDevExt, pWait);
|
---|
[3657] | 2207 | return rc;
|
---|
| 2208 | }
|
---|
| 2209 |
|
---|
| 2210 | if (fInterruptible)
|
---|
[68550] | 2211 | rc = RTSemEventMultiWaitNoResume(pWait->Event, cMsTimeout == UINT32_MAX ? RT_INDEFINITE_WAIT : cMsTimeout);
|
---|
[3657] | 2212 | else
|
---|
[68550] | 2213 | rc = RTSemEventMultiWait(pWait->Event, cMsTimeout == UINT32_MAX ? RT_INDEFINITE_WAIT : cMsTimeout);
|
---|
[6032] | 2214 |
|
---|
[3657] | 2215 | /*
|
---|
[6032] | 2216 | * There is one special case here and that's when the semaphore is
|
---|
[3657] | 2217 | * destroyed upon device driver unload. This shouldn't happen of course,
|
---|
| 2218 | * but in case it does, just get out of here ASAP.
|
---|
| 2219 | */
|
---|
| 2220 | if (rc == VERR_SEM_DESTROYED)
|
---|
| 2221 | return rc;
|
---|
| 2222 |
|
---|
| 2223 | /*
|
---|
| 2224 | * Unlink the wait item and dispose of it.
|
---|
| 2225 | */
|
---|
[40806] | 2226 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[31720] | 2227 | fResEvents = pWait->fResEvents;
|
---|
[58053] | 2228 | vgdrvWaitFreeLocked(pDevExt, pWait);
|
---|
[52618] | 2229 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[3657] | 2230 |
|
---|
| 2231 | /*
|
---|
| 2232 | * Now deal with the return code.
|
---|
| 2233 | */
|
---|
[68550] | 2234 | if ( fResEvents
|
---|
| 2235 | && fResEvents != UINT32_MAX)
|
---|
[3657] | 2236 | {
|
---|
[68550] | 2237 | pInfo->u.Out.fEvents = fResEvents;
|
---|
[3657] | 2238 | if (fReqEvents & ~((uint32_t)1 << iEvent))
|
---|
[68550] | 2239 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x\n", pInfo->u.Out.fEvents));
|
---|
[3657] | 2240 | else
|
---|
[68550] | 2241 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x/%d\n", pInfo->u.Out.fEvents, iEvent));
|
---|
[3657] | 2242 | rc = VINF_SUCCESS;
|
---|
| 2243 | }
|
---|
[21491] | 2244 | else if ( fResEvents == UINT32_MAX
|
---|
| 2245 | || rc == VERR_INTERRUPTED)
|
---|
| 2246 | {
|
---|
[26631] | 2247 | rc = VERR_INTERRUPTED;
|
---|
[54615] | 2248 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_INTERRUPTED\n"));
|
---|
[21491] | 2249 | }
|
---|
[3657] | 2250 | else if (rc == VERR_TIMEOUT)
|
---|
[54615] | 2251 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_TIMEOUT (2)\n"));
|
---|
[3657] | 2252 | else
|
---|
| 2253 | {
|
---|
| 2254 | if (RT_SUCCESS(rc))
|
---|
| 2255 | {
|
---|
[54615] | 2256 | LogRelMax(32, ("VBOXGUEST_IOCTL_WAITEVENT: returns %Rrc but no events!\n", rc));
|
---|
[3657] | 2257 | rc = VERR_INTERNAL_ERROR;
|
---|
| 2258 | }
|
---|
[54615] | 2259 | LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %Rrc\n", rc));
|
---|
[3657] | 2260 | }
|
---|
| 2261 |
|
---|
| 2262 | return rc;
|
---|
| 2263 | }
|
---|
| 2264 |
|
---|
| 2265 |
|
---|
[67802] | 2266 | /** @todo the semantics of this IoCtl have been tightened, so that no calls to
|
---|
| 2267 | * VBOXGUEST_IOCTL_WAITEVENT are allowed in a session after it has been
|
---|
| 2268 | * called. Change the code to make calls to VBOXGUEST_IOCTL_WAITEVENT made
|
---|
| 2269 | * after that to return VERR_INTERRUPTED or something appropriate. */
|
---|
[58053] | 2270 | static int vgdrvIoCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
|
---|
[21491] | 2271 | {
|
---|
[22128] | 2272 | PVBOXGUESTWAIT pWait;
|
---|
[32449] | 2273 | PVBOXGUESTWAIT pSafe;
|
---|
[33059] | 2274 | int rc = 0;
|
---|
[50372] | 2275 | /* Was as least one WAITEVENT in process for this session? If not we
|
---|
| 2276 | * set a flag that the next call should be interrupted immediately. This
|
---|
| 2277 | * is needed so that a user thread can reliably interrupt another one in a
|
---|
| 2278 | * WAITEVENT loop. */
|
---|
| 2279 | bool fCancelledOne = false;
|
---|
[21491] | 2280 |
|
---|
[54615] | 2281 | LogFlow(("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS\n"));
|
---|
[21491] | 2282 |
|
---|
| 2283 | /*
|
---|
| 2284 | * Walk the event list and wake up anyone with a matching session.
|
---|
| 2285 | */
|
---|
[40806] | 2286 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[32449] | 2287 | RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
|
---|
[22128] | 2288 | {
|
---|
[21491] | 2289 | if (pWait->pSession == pSession)
|
---|
| 2290 | {
|
---|
[50372] | 2291 | fCancelledOne = true;
|
---|
[21491] | 2292 | pWait->fResEvents = UINT32_MAX;
|
---|
[32449] | 2293 | RTListNodeRemove(&pWait->ListNode);
|
---|
| 2294 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
| 2295 | RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
|
---|
| 2296 | #else
|
---|
[21491] | 2297 | rc |= RTSemEventMultiSignal(pWait->Event);
|
---|
[32449] | 2298 | RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
|
---|
| 2299 | #endif
|
---|
[21491] | 2300 | }
|
---|
[32449] | 2301 | }
|
---|
[50372] | 2302 | if (!fCancelledOne)
|
---|
| 2303 | pSession->fPendingCancelWaitEvents = true;
|
---|
[52618] | 2304 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[33059] | 2305 | Assert(rc == 0);
|
---|
[48311] | 2306 | NOREF(rc);
|
---|
[21491] | 2307 |
|
---|
[32449] | 2308 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
[58053] | 2309 | VGDrvCommonWaitDoWakeUps(pDevExt);
|
---|
[32449] | 2310 | #endif
|
---|
| 2311 |
|
---|
[21491] | 2312 | return VINF_SUCCESS;
|
---|
| 2313 | }
|
---|
| 2314 |
|
---|
[54615] | 2315 |
|
---|
[39890] | 2316 | /**
|
---|
| 2317 | * Checks if the VMM request is allowed in the context of the given session.
|
---|
| 2318 | *
|
---|
| 2319 | * @returns VINF_SUCCESS or VERR_PERMISSION_DENIED.
|
---|
[58089] | 2320 | * @param pDevExt The device extension.
|
---|
[39890] | 2321 | * @param pSession The calling session.
|
---|
| 2322 | * @param enmType The request type.
|
---|
| 2323 | * @param pReqHdr The request.
|
---|
| 2324 | */
|
---|
[58053] | 2325 | static int vgdrvCheckIfVmmReqIsAllowed(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VMMDevRequestType enmType,
|
---|
| 2326 | VMMDevRequestHeader const *pReqHdr)
|
---|
[39890] | 2327 | {
|
---|
| 2328 | /*
|
---|
| 2329 | * Categorize the request being made.
|
---|
| 2330 | */
|
---|
| 2331 | /** @todo This need quite some more work! */
|
---|
| 2332 | enum
|
---|
| 2333 | {
|
---|
| 2334 | kLevel_Invalid, kLevel_NoOne, kLevel_OnlyVBoxGuest, kLevel_OnlyKernel, kLevel_TrustedUsers, kLevel_AllUsers
|
---|
| 2335 | } enmRequired;
|
---|
[62853] | 2336 | RT_NOREF1(pDevExt);
|
---|
| 2337 |
|
---|
[39890] | 2338 | switch (enmType)
|
---|
| 2339 | {
|
---|
| 2340 | /*
|
---|
| 2341 | * Deny access to anything we don't know or provide specialized I/O controls for.
|
---|
| 2342 | */
|
---|
| 2343 | #ifdef VBOX_WITH_HGCM
|
---|
| 2344 | case VMMDevReq_HGCMConnect:
|
---|
| 2345 | case VMMDevReq_HGCMDisconnect:
|
---|
| 2346 | # ifdef VBOX_WITH_64_BITS_GUESTS
|
---|
[77056] | 2347 | case VMMDevReq_HGCMCall64:
|
---|
| 2348 | # endif
|
---|
[39890] | 2349 | case VMMDevReq_HGCMCall32:
|
---|
| 2350 | case VMMDevReq_HGCMCancel:
|
---|
| 2351 | case VMMDevReq_HGCMCancel2:
|
---|
| 2352 | #endif /* VBOX_WITH_HGCM */
|
---|
[54601] | 2353 | case VMMDevReq_SetGuestCapabilities:
|
---|
[39890] | 2354 | default:
|
---|
| 2355 | enmRequired = kLevel_NoOne;
|
---|
| 2356 | break;
|
---|
[21491] | 2357 |
|
---|
[39890] | 2358 | /*
|
---|
| 2359 | * There are a few things only this driver can do (and it doesn't use
|
---|
| 2360 | * the VMMRequst I/O control route anyway, but whatever).
|
---|
| 2361 | */
|
---|
| 2362 | case VMMDevReq_ReportGuestInfo:
|
---|
| 2363 | case VMMDevReq_ReportGuestInfo2:
|
---|
| 2364 | case VMMDevReq_GetHypervisorInfo:
|
---|
| 2365 | case VMMDevReq_SetHypervisorInfo:
|
---|
| 2366 | case VMMDevReq_RegisterPatchMemory:
|
---|
| 2367 | case VMMDevReq_DeregisterPatchMemory:
|
---|
| 2368 | case VMMDevReq_GetMemBalloonChangeRequest:
|
---|
[94315] | 2369 | case VMMDevReq_ChangeMemBalloon:
|
---|
[39890] | 2370 | enmRequired = kLevel_OnlyVBoxGuest;
|
---|
| 2371 | break;
|
---|
| 2372 |
|
---|
| 2373 | /*
|
---|
| 2374 | * Trusted users apps only.
|
---|
| 2375 | */
|
---|
| 2376 | case VMMDevReq_QueryCredentials:
|
---|
| 2377 | case VMMDevReq_ReportCredentialsJudgement:
|
---|
| 2378 | case VMMDevReq_RegisterSharedModule:
|
---|
| 2379 | case VMMDevReq_UnregisterSharedModule:
|
---|
| 2380 | case VMMDevReq_WriteCoreDump:
|
---|
| 2381 | case VMMDevReq_GetCpuHotPlugRequest:
|
---|
| 2382 | case VMMDevReq_SetCpuHotPlugStatus:
|
---|
| 2383 | case VMMDevReq_CheckSharedModules:
|
---|
| 2384 | case VMMDevReq_GetPageSharingStatus:
|
---|
| 2385 | case VMMDevReq_DebugIsPageShared:
|
---|
| 2386 | case VMMDevReq_ReportGuestStats:
|
---|
[47294] | 2387 | case VMMDevReq_ReportGuestUserState:
|
---|
[39890] | 2388 | case VMMDevReq_GetStatisticsChangeRequest:
|
---|
| 2389 | enmRequired = kLevel_TrustedUsers;
|
---|
| 2390 | break;
|
---|
| 2391 |
|
---|
| 2392 | /*
|
---|
| 2393 | * Anyone.
|
---|
| 2394 | */
|
---|
| 2395 | case VMMDevReq_GetMouseStatus:
|
---|
| 2396 | case VMMDevReq_SetMouseStatus:
|
---|
| 2397 | case VMMDevReq_SetPointerShape:
|
---|
| 2398 | case VMMDevReq_GetHostVersion:
|
---|
| 2399 | case VMMDevReq_Idle:
|
---|
| 2400 | case VMMDevReq_GetHostTime:
|
---|
| 2401 | case VMMDevReq_SetPowerStatus:
|
---|
| 2402 | case VMMDevReq_AcknowledgeEvents:
|
---|
| 2403 | case VMMDevReq_CtlGuestFilterMask:
|
---|
| 2404 | case VMMDevReq_ReportGuestStatus:
|
---|
| 2405 | case VMMDevReq_GetDisplayChangeRequest:
|
---|
| 2406 | case VMMDevReq_VideoModeSupported:
|
---|
| 2407 | case VMMDevReq_GetHeightReduction:
|
---|
| 2408 | case VMMDevReq_GetDisplayChangeRequest2:
|
---|
| 2409 | case VMMDevReq_VideoModeSupported2:
|
---|
| 2410 | case VMMDevReq_VideoAccelEnable:
|
---|
| 2411 | case VMMDevReq_VideoAccelFlush:
|
---|
| 2412 | case VMMDevReq_VideoSetVisibleRegion:
|
---|
[83142] | 2413 | case VMMDevReq_VideoUpdateMonitorPositions:
|
---|
[44130] | 2414 | case VMMDevReq_GetDisplayChangeRequestEx:
|
---|
[72352] | 2415 | case VMMDevReq_GetDisplayChangeRequestMulti:
|
---|
[39890] | 2416 | case VMMDevReq_GetSeamlessChangeRequest:
|
---|
| 2417 | case VMMDevReq_GetVRDPChangeRequest:
|
---|
| 2418 | case VMMDevReq_LogString:
|
---|
| 2419 | case VMMDevReq_GetSessionId:
|
---|
| 2420 | enmRequired = kLevel_AllUsers;
|
---|
| 2421 | break;
|
---|
| 2422 |
|
---|
| 2423 | /*
|
---|
| 2424 | * Depends on the request parameters...
|
---|
| 2425 | */
|
---|
| 2426 | /** @todo this have to be changed into an I/O control and the facilities
|
---|
| 2427 | * tracked in the session so they can automatically be failed when the
|
---|
| 2428 | * session terminates without reporting the new status.
|
---|
| 2429 | *
|
---|
| 2430 | * The information presented by IGuest is not reliable without this! */
|
---|
| 2431 | case VMMDevReq_ReportGuestCapabilities:
|
---|
| 2432 | switch (((VMMDevReportGuestStatus const *)pReqHdr)->guestStatus.facility)
|
---|
| 2433 | {
|
---|
| 2434 | case VBoxGuestFacilityType_All:
|
---|
| 2435 | case VBoxGuestFacilityType_VBoxGuestDriver:
|
---|
| 2436 | enmRequired = kLevel_OnlyVBoxGuest;
|
---|
| 2437 | break;
|
---|
| 2438 | case VBoxGuestFacilityType_VBoxService:
|
---|
| 2439 | enmRequired = kLevel_TrustedUsers;
|
---|
| 2440 | break;
|
---|
| 2441 | case VBoxGuestFacilityType_VBoxTrayClient:
|
---|
| 2442 | case VBoxGuestFacilityType_Seamless:
|
---|
| 2443 | case VBoxGuestFacilityType_Graphics:
|
---|
| 2444 | default:
|
---|
| 2445 | enmRequired = kLevel_AllUsers;
|
---|
| 2446 | break;
|
---|
| 2447 | }
|
---|
| 2448 | break;
|
---|
| 2449 | }
|
---|
| 2450 |
|
---|
| 2451 | /*
|
---|
| 2452 | * Check against the session.
|
---|
| 2453 | */
|
---|
| 2454 | switch (enmRequired)
|
---|
| 2455 | {
|
---|
| 2456 | default:
|
---|
| 2457 | case kLevel_NoOne:
|
---|
| 2458 | break;
|
---|
| 2459 | case kLevel_OnlyVBoxGuest:
|
---|
| 2460 | case kLevel_OnlyKernel:
|
---|
| 2461 | if (pSession->R0Process == NIL_RTR0PROCESS)
|
---|
| 2462 | return VINF_SUCCESS;
|
---|
| 2463 | break;
|
---|
| 2464 | case kLevel_TrustedUsers:
|
---|
[70608] | 2465 | if (pSession->fUserSession)
|
---|
| 2466 | break;
|
---|
[77728] | 2467 | RT_FALL_THRU();
|
---|
[39890] | 2468 | case kLevel_AllUsers:
|
---|
| 2469 | return VINF_SUCCESS;
|
---|
| 2470 | }
|
---|
| 2471 |
|
---|
| 2472 | return VERR_PERMISSION_DENIED;
|
---|
| 2473 | }
|
---|
| 2474 |
|
---|
[68550] | 2475 | static int vgdrvIoCtl_VMMDevRequest(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
| 2476 | VMMDevRequestHeader *pReqHdr, size_t cbData)
|
---|
[3657] | 2477 | {
|
---|
[31752] | 2478 | int rc;
|
---|
| 2479 | VMMDevRequestHeader *pReqCopy;
|
---|
| 2480 |
|
---|
[3657] | 2481 | /*
|
---|
| 2482 | * Validate the header and request size.
|
---|
| 2483 | */
|
---|
[21102] | 2484 | const VMMDevRequestType enmType = pReqHdr->requestType;
|
---|
| 2485 | const uint32_t cbReq = pReqHdr->size;
|
---|
[51224] | 2486 | const uint32_t cbMinSize = (uint32_t)vmmdevGetRequestSize(enmType);
|
---|
[31720] | 2487 |
|
---|
[54615] | 2488 | LogFlow(("VBOXGUEST_IOCTL_VMMREQUEST: type %d\n", pReqHdr->requestType));
|
---|
[31720] | 2489 |
|
---|
[3657] | 2490 | if (cbReq < cbMinSize)
|
---|
| 2491 | {
|
---|
[54615] | 2492 | LogRel(("VBOXGUEST_IOCTL_VMMREQUEST: invalid hdr size %#x, expected >= %#x; type=%#x!!\n",
|
---|
[54237] | 2493 | cbReq, cbMinSize, enmType));
|
---|
[3657] | 2494 | return VERR_INVALID_PARAMETER;
|
---|
| 2495 | }
|
---|
| 2496 | if (cbReq > cbData)
|
---|
| 2497 | {
|
---|
[54615] | 2498 | LogRel(("VBOXGUEST_IOCTL_VMMREQUEST: invalid size %#x, expected >= %#x (hdr); type=%#x!!\n",
|
---|
[54237] | 2499 | cbData, cbReq, enmType));
|
---|
[3657] | 2500 | return VERR_INVALID_PARAMETER;
|
---|
| 2501 | }
|
---|
[68654] | 2502 | rc = VbglGR0Verify(pReqHdr, cbData);
|
---|
[23916] | 2503 | if (RT_FAILURE(rc))
|
---|
| 2504 | {
|
---|
[54615] | 2505 | Log(("VBOXGUEST_IOCTL_VMMREQUEST: invalid header: size %#x, expected >= %#x (hdr); type=%#x; rc=%Rrc!!\n",
|
---|
[54237] | 2506 | cbData, cbReq, enmType, rc));
|
---|
[23916] | 2507 | return rc;
|
---|
| 2508 | }
|
---|
[3657] | 2509 |
|
---|
[58053] | 2510 | rc = vgdrvCheckIfVmmReqIsAllowed(pDevExt, pSession, enmType, pReqHdr);
|
---|
[39890] | 2511 | if (RT_FAILURE(rc))
|
---|
| 2512 | {
|
---|
[54615] | 2513 | Log(("VBOXGUEST_IOCTL_VMMREQUEST: Operation not allowed! type=%#x rc=%Rrc\n", enmType, rc));
|
---|
[39890] | 2514 | return rc;
|
---|
| 2515 | }
|
---|
| 2516 |
|
---|
[3657] | 2517 | /*
|
---|
| 2518 | * Make a copy of the request in the physical memory heap so
|
---|
| 2519 | * the VBoxGuestLibrary can more easily deal with the request.
|
---|
| 2520 | * (This is really a waste of time since the OS or the OS specific
|
---|
| 2521 | * code has already buffered or locked the input/output buffer, but
|
---|
| 2522 | * it does makes things a bit simpler wrt to phys address.)
|
---|
| 2523 | */
|
---|
[68654] | 2524 | rc = VbglR0GRAlloc(&pReqCopy, cbReq, enmType);
|
---|
[3657] | 2525 | if (RT_FAILURE(rc))
|
---|
| 2526 | {
|
---|
[54615] | 2527 | Log(("VBOXGUEST_IOCTL_VMMREQUEST: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
|
---|
[54237] | 2528 | cbReq, cbReq, rc));
|
---|
[3657] | 2529 | return rc;
|
---|
| 2530 | }
|
---|
[21102] | 2531 | memcpy(pReqCopy, pReqHdr, cbReq);
|
---|
[68550] | 2532 | Assert(pReqCopy->reserved1 == cbReq);
|
---|
| 2533 | pReqCopy->reserved1 = 0; /* VGDrvCommonIoCtl or caller sets cbOut, so clear it. */
|
---|
[70873] | 2534 | pReqCopy->fRequestor = pSession->fRequestor;
|
---|
[6032] | 2535 |
|
---|
[21102] | 2536 | if (enmType == VMMDevReq_GetMouseStatus) /* clear poll condition. */
|
---|
| 2537 | pSession->u32MousePosChangedSeq = ASMAtomicUoReadU32(&pDevExt->u32MousePosChangedSeq);
|
---|
| 2538 |
|
---|
[68654] | 2539 | rc = VbglR0GRPerform(pReqCopy);
|
---|
[54615] | 2540 | if ( RT_SUCCESS(rc)
|
---|
| 2541 | && RT_SUCCESS(pReqCopy->rc))
|
---|
[3657] | 2542 | {
|
---|
| 2543 | Assert(rc != VINF_HGCM_ASYNC_EXECUTE);
|
---|
| 2544 | Assert(pReqCopy->rc != VINF_HGCM_ASYNC_EXECUTE);
|
---|
| 2545 |
|
---|
| 2546 | memcpy(pReqHdr, pReqCopy, cbReq);
|
---|
[68550] | 2547 | pReqHdr->reserved1 = cbReq; /* preserve cbOut */
|
---|
[3657] | 2548 | }
|
---|
| 2549 | else if (RT_FAILURE(rc))
|
---|
[68654] | 2550 | Log(("VBOXGUEST_IOCTL_VMMREQUEST: VbglR0GRPerform - rc=%Rrc!\n", rc));
|
---|
[3657] | 2551 | else
|
---|
| 2552 | {
|
---|
[54615] | 2553 | Log(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed; VMMDev rc=%Rrc!\n", pReqCopy->rc));
|
---|
[3657] | 2554 | rc = pReqCopy->rc;
|
---|
| 2555 | }
|
---|
| 2556 |
|
---|
[68654] | 2557 | VbglR0GRFree(pReqCopy);
|
---|
[3657] | 2558 | return rc;
|
---|
| 2559 | }
|
---|
| 2560 |
|
---|
| 2561 |
|
---|
[11820] | 2562 | #ifdef VBOX_WITH_HGCM
|
---|
[3657] | 2563 |
|
---|
[14367] | 2564 | AssertCompile(RT_INDEFINITE_WAIT == (uint32_t)RT_INDEFINITE_WAIT); /* assumed by code below */
|
---|
| 2565 |
|
---|
[58053] | 2566 | /** Worker for vgdrvHgcmAsyncWaitCallback*. */
|
---|
| 2567 | static int vgdrvHgcmAsyncWaitCallbackWorker(VMMDevHGCMRequestHeader volatile *pHdr, PVBOXGUESTDEVEXT pDevExt,
|
---|
| 2568 | bool fInterruptible, uint32_t cMillies)
|
---|
[14221] | 2569 | {
|
---|
[31720] | 2570 | int rc;
|
---|
[3657] | 2571 |
|
---|
[14221] | 2572 | /*
|
---|
| 2573 | * Check to see if the condition was met by the time we got here.
|
---|
| 2574 | *
|
---|
| 2575 | * We create a simple poll loop here for dealing with out-of-memory
|
---|
| 2576 | * conditions since the caller isn't necessarily able to deal with
|
---|
| 2577 | * us returning too early.
|
---|
| 2578 | */
|
---|
| 2579 | PVBOXGUESTWAIT pWait;
|
---|
| 2580 | for (;;)
|
---|
| 2581 | {
|
---|
[40806] | 2582 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[14221] | 2583 | if ((pHdr->fu32Flags & VBOX_HGCM_REQ_DONE) != 0)
|
---|
| 2584 | {
|
---|
[52618] | 2585 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[21506] | 2586 | return VINF_SUCCESS;
|
---|
[14221] | 2587 | }
|
---|
[52618] | 2588 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[14221] | 2589 |
|
---|
[58053] | 2590 | pWait = vgdrvWaitAlloc(pDevExt, NULL);
|
---|
[14221] | 2591 | if (pWait)
|
---|
| 2592 | break;
|
---|
[14310] | 2593 | if (fInterruptible)
|
---|
[21506] | 2594 | return VERR_INTERRUPTED;
|
---|
[14310] | 2595 | RTThreadSleep(1);
|
---|
[14221] | 2596 | }
|
---|
| 2597 | pWait->fReqEvents = VMMDEV_EVENT_HGCM;
|
---|
| 2598 | pWait->pHGCMReq = pHdr;
|
---|
| 2599 |
|
---|
| 2600 | /*
|
---|
| 2601 | * Re-enter the spinlock and re-check for the condition.
|
---|
| 2602 | * If the condition is met, return.
|
---|
| 2603 | * Otherwise link us into the HGCM wait list and go to sleep.
|
---|
| 2604 | */
|
---|
[40806] | 2605 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[32449] | 2606 | RTListAppend(&pDevExt->HGCMWaitList, &pWait->ListNode);
|
---|
[14221] | 2607 | if ((pHdr->fu32Flags & VBOX_HGCM_REQ_DONE) != 0)
|
---|
| 2608 | {
|
---|
[58053] | 2609 | vgdrvWaitFreeLocked(pDevExt, pWait);
|
---|
[52618] | 2610 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[21506] | 2611 | return VINF_SUCCESS;
|
---|
[14221] | 2612 | }
|
---|
[52618] | 2613 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[14221] | 2614 |
|
---|
[14276] | 2615 | if (fInterruptible)
|
---|
[14367] | 2616 | rc = RTSemEventMultiWaitNoResume(pWait->Event, cMillies);
|
---|
[14276] | 2617 | else
|
---|
[14367] | 2618 | rc = RTSemEventMultiWait(pWait->Event, cMillies);
|
---|
[21506] | 2619 | if (rc == VERR_SEM_DESTROYED)
|
---|
| 2620 | return rc;
|
---|
[14221] | 2621 |
|
---|
| 2622 | /*
|
---|
| 2623 | * Unlink, free and return.
|
---|
| 2624 | */
|
---|
[54615] | 2625 | if ( RT_FAILURE(rc)
|
---|
| 2626 | && rc != VERR_TIMEOUT
|
---|
| 2627 | && ( !fInterruptible
|
---|
| 2628 | || rc != VERR_INTERRUPTED))
|
---|
[58053] | 2629 | LogRel(("vgdrvHgcmAsyncWaitCallback: wait failed! %Rrc\n", rc));
|
---|
[14221] | 2630 |
|
---|
[58053] | 2631 | vgdrvWaitFreeUnlocked(pDevExt, pWait);
|
---|
[21506] | 2632 | return rc;
|
---|
[14221] | 2633 | }
|
---|
[14276] | 2634 |
|
---|
[14367] | 2635 |
|
---|
[14276] | 2636 | /**
|
---|
| 2637 | * This is a callback for dealing with async waits.
|
---|
| 2638 | *
|
---|
[58053] | 2639 | * It operates in a manner similar to vgdrvIoCtl_WaitEvent.
|
---|
[14276] | 2640 | */
|
---|
[58053] | 2641 | static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdr, void *pvUser, uint32_t u32User)
|
---|
[14276] | 2642 | {
|
---|
| 2643 | PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
|
---|
[58053] | 2644 | LogFlow(("vgdrvHgcmAsyncWaitCallback: requestType=%d\n", pHdr->header.requestType));
|
---|
| 2645 | return vgdrvHgcmAsyncWaitCallbackWorker((VMMDevHGCMRequestHeader volatile *)pHdr, pDevExt,
|
---|
| 2646 | false /* fInterruptible */, u32User /* cMillies */);
|
---|
[14276] | 2647 | }
|
---|
| 2648 |
|
---|
[14367] | 2649 |
|
---|
[14276] | 2650 | /**
|
---|
| 2651 | * This is a callback for dealing with async waits with a timeout.
|
---|
| 2652 | *
|
---|
[58053] | 2653 | * It operates in a manner similar to vgdrvIoCtl_WaitEvent.
|
---|
[14276] | 2654 | */
|
---|
[58053] | 2655 | static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallbackInterruptible(VMMDevHGCMRequestHeader *pHdr, void *pvUser, uint32_t u32User)
|
---|
[14276] | 2656 | {
|
---|
| 2657 | PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
|
---|
[58053] | 2658 | LogFlow(("vgdrvHgcmAsyncWaitCallbackInterruptible: requestType=%d\n", pHdr->header.requestType));
|
---|
| 2659 | return vgdrvHgcmAsyncWaitCallbackWorker((VMMDevHGCMRequestHeader volatile *)pHdr, pDevExt,
|
---|
| 2660 | true /* fInterruptible */, u32User /* cMillies */);
|
---|
[14276] | 2661 | }
|
---|
| 2662 |
|
---|
[14367] | 2663 |
|
---|
[68550] | 2664 | static int vgdrvIoCtl_HGCMConnect(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCHGCMCONNECT pInfo)
|
---|
[3657] | 2665 | {
|
---|
[31720] | 2666 | int rc;
|
---|
[68550] | 2667 | HGCMCLIENTID idClient = 0;
|
---|
[31720] | 2668 |
|
---|
[3657] | 2669 | /*
|
---|
[6032] | 2670 | * The VbglHGCMConnect call will invoke the callback if the HGCM
|
---|
| 2671 | * call is performed in an ASYNC fashion. The function is not able
|
---|
[3657] | 2672 | * to deal with cancelled requests.
|
---|
| 2673 | */
|
---|
[54615] | 2674 | Log(("VBOXGUEST_IOCTL_HGCM_CONNECT: %.128s\n",
|
---|
[68550] | 2675 | pInfo->u.In.Loc.type == VMMDevHGCMLoc_LocalHost || pInfo->u.In.Loc.type == VMMDevHGCMLoc_LocalHost_Existing
|
---|
| 2676 | ? pInfo->u.In.Loc.u.host.achName : "<not local host>"));
|
---|
[3657] | 2677 |
|
---|
[70873] | 2678 | rc = VbglR0HGCMInternalConnect(&pInfo->u.In.Loc, pSession->fRequestor, &idClient,
|
---|
| 2679 | vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
|
---|
[68550] | 2680 | Log(("VBOXGUEST_IOCTL_HGCM_CONNECT: idClient=%RX32 (rc=%Rrc)\n", idClient, rc));
|
---|
[3657] | 2681 | if (RT_SUCCESS(rc))
|
---|
| 2682 | {
|
---|
[68550] | 2683 | /*
|
---|
| 2684 | * Append the client id to the client id table.
|
---|
| 2685 | * If the table has somehow become filled up, we'll disconnect the session.
|
---|
| 2686 | */
|
---|
| 2687 | unsigned i;
|
---|
| 2688 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
| 2689 | for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
|
---|
| 2690 | if (!pSession->aHGCMClientIds[i])
|
---|
[3657] | 2691 | {
|
---|
[68550] | 2692 | pSession->aHGCMClientIds[i] = idClient;
|
---|
| 2693 | break;
|
---|
[3657] | 2694 | }
|
---|
[68550] | 2695 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
| 2696 | if (i >= RT_ELEMENTS(pSession->aHGCMClientIds))
|
---|
| 2697 | {
|
---|
| 2698 | LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CONNECT: too many HGCMConnect calls for one session!\n"));
|
---|
[70873] | 2699 | VbglR0HGCMInternalDisconnect(idClient, pSession->fRequestor, vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
|
---|
[68550] | 2700 |
|
---|
| 2701 | pInfo->u.Out.idClient = 0;
|
---|
| 2702 | return VERR_TOO_MANY_OPEN_FILES;
|
---|
[3657] | 2703 | }
|
---|
| 2704 | }
|
---|
[68550] | 2705 | pInfo->u.Out.idClient = idClient;
|
---|
[3657] | 2706 | return rc;
|
---|
| 2707 | }
|
---|
| 2708 |
|
---|
| 2709 |
|
---|
[68550] | 2710 | static int vgdrvIoCtl_HGCMDisconnect(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCHGCMDISCONNECT pInfo)
|
---|
[3657] | 2711 | {
|
---|
| 2712 | /*
|
---|
| 2713 | * Validate the client id and invalidate its entry while we're in the call.
|
---|
| 2714 | */
|
---|
[31752] | 2715 | int rc;
|
---|
[68550] | 2716 | const uint32_t idClient = pInfo->u.In.idClient;
|
---|
[31752] | 2717 | unsigned i;
|
---|
[40806] | 2718 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
[3657] | 2719 | for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
|
---|
[68550] | 2720 | if (pSession->aHGCMClientIds[i] == idClient)
|
---|
[3657] | 2721 | {
|
---|
| 2722 | pSession->aHGCMClientIds[i] = UINT32_MAX;
|
---|
| 2723 | break;
|
---|
| 2724 | }
|
---|
[52618] | 2725 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
[3657] | 2726 | if (i >= RT_ELEMENTS(pSession->aHGCMClientIds))
|
---|
| 2727 | {
|
---|
[68550] | 2728 | LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_DISCONNECT: idClient=%RX32\n", idClient));
|
---|
[3657] | 2729 | return VERR_INVALID_HANDLE;
|
---|
| 2730 | }
|
---|
| 2731 |
|
---|
| 2732 | /*
|
---|
[6032] | 2733 | * The VbglHGCMConnect call will invoke the callback if the HGCM
|
---|
| 2734 | * call is performed in an ASYNC fashion. The function is not able
|
---|
[3657] | 2735 | * to deal with cancelled requests.
|
---|
| 2736 | */
|
---|
[68550] | 2737 | Log(("VBOXGUEST_IOCTL_HGCM_DISCONNECT: idClient=%RX32\n", idClient));
|
---|
[70873] | 2738 | rc = VbglR0HGCMInternalDisconnect(idClient, pSession->fRequestor, vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
|
---|
[68550] | 2739 | LogFlow(("VBOXGUEST_IOCTL_HGCM_DISCONNECT: rc=%Rrc\n", rc));
|
---|
[3657] | 2740 |
|
---|
| 2741 | /* Update the client id array according to the result. */
|
---|
[40806] | 2742 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
[3657] | 2743 | if (pSession->aHGCMClientIds[i] == UINT32_MAX)
|
---|
[68550] | 2744 | pSession->aHGCMClientIds[i] = RT_SUCCESS(rc) ? 0 : idClient;
|
---|
[52618] | 2745 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
[3657] | 2746 |
|
---|
| 2747 | return rc;
|
---|
| 2748 | }
|
---|
| 2749 |
|
---|
| 2750 |
|
---|
[68550] | 2751 | static int vgdrvIoCtl_HGCMCallInner(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCHGCMCALL pInfo,
|
---|
| 2752 | uint32_t cMillies, bool fInterruptible, bool f32bit, bool fUserData,
|
---|
| 2753 | size_t cbExtra, size_t cbData)
|
---|
[3657] | 2754 | {
|
---|
[31752] | 2755 | const uint32_t u32ClientId = pInfo->u32ClientID;
|
---|
| 2756 | uint32_t fFlags;
|
---|
| 2757 | size_t cbActual;
|
---|
| 2758 | unsigned i;
|
---|
| 2759 | int rc;
|
---|
[31720] | 2760 |
|
---|
[3657] | 2761 | /*
|
---|
| 2762 | * Some more validations.
|
---|
| 2763 | */
|
---|
[75547] | 2764 | if (RT_LIKELY(pInfo->cParms <= VMMDEV_MAX_HGCM_PARMS)) /* (Just make sure it doesn't overflow the next check.) */
|
---|
| 2765 | { /* likely */}
|
---|
| 2766 | else
|
---|
[3657] | 2767 | {
|
---|
[54615] | 2768 | LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cParm=%RX32 is not sane\n", pInfo->cParms));
|
---|
[3657] | 2769 | return VERR_INVALID_PARAMETER;
|
---|
| 2770 | }
|
---|
[31720] | 2771 |
|
---|
| 2772 | cbActual = cbExtra + sizeof(*pInfo);
|
---|
[17210] | 2773 | #ifdef RT_ARCH_AMD64
|
---|
| 2774 | if (f32bit)
|
---|
| 2775 | cbActual += pInfo->cParms * sizeof(HGCMFunctionParameter32);
|
---|
| 2776 | else
|
---|
| 2777 | #endif
|
---|
| 2778 | cbActual += pInfo->cParms * sizeof(HGCMFunctionParameter);
|
---|
[75547] | 2779 | if (RT_LIKELY(cbData >= cbActual))
|
---|
| 2780 | { /* likely */}
|
---|
| 2781 | else
|
---|
[3657] | 2782 | {
|
---|
[54615] | 2783 | LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cbData=%#zx (%zu) required size is %#zx (%zu)\n",
|
---|
[54237] | 2784 | cbData, cbData, cbActual, cbActual));
|
---|
[3657] | 2785 | return VERR_INVALID_PARAMETER;
|
---|
| 2786 | }
|
---|
[68550] | 2787 | pInfo->Hdr.cbOut = (uint32_t)cbActual;
|
---|
[3657] | 2788 |
|
---|
| 2789 | /*
|
---|
| 2790 | * Validate the client id.
|
---|
| 2791 | */
|
---|
[40806] | 2792 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
[3657] | 2793 | for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
|
---|
| 2794 | if (pSession->aHGCMClientIds[i] == u32ClientId)
|
---|
| 2795 | break;
|
---|
[52618] | 2796 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
[75547] | 2797 | if (RT_LIKELY(i < RT_ELEMENTS(pSession->aHGCMClientIds)))
|
---|
| 2798 | { /* likely */}
|
---|
| 2799 | else
|
---|
[3657] | 2800 | {
|
---|
[54615] | 2801 | LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CALL: Invalid handle. u32Client=%RX32\n", u32ClientId));
|
---|
[3657] | 2802 | return VERR_INVALID_HANDLE;
|
---|
| 2803 | }
|
---|
| 2804 |
|
---|
| 2805 | /*
|
---|
[6032] | 2806 | * The VbglHGCMCall call will invoke the callback if the HGCM
|
---|
| 2807 | * call is performed in an ASYNC fashion. This function can
|
---|
[3657] | 2808 | * deal with cancelled requests, so we let user more requests
|
---|
| 2809 | * be interruptible (should add a flag for this later I guess).
|
---|
| 2810 | */
|
---|
[54615] | 2811 | LogFlow(("VBOXGUEST_IOCTL_HGCM_CALL: u32Client=%RX32\n", pInfo->u32ClientID));
|
---|
[40483] | 2812 | fFlags = !fUserData && pSession->R0Process == NIL_RTR0PROCESS ? VBGLR0_HGCMCALL_F_KERNEL : VBGLR0_HGCMCALL_F_USER;
|
---|
[53293] | 2813 | uint32_t cbInfo = (uint32_t)(cbData - cbExtra);
|
---|
[100267] | 2814 | #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64)
|
---|
[17210] | 2815 | if (f32bit)
|
---|
[17196] | 2816 | {
|
---|
[17210] | 2817 | if (fInterruptible)
|
---|
[70873] | 2818 | rc = VbglR0HGCMInternalCall32(pInfo, cbInfo, fFlags, pSession->fRequestor,
|
---|
| 2819 | vgdrvHgcmAsyncWaitCallbackInterruptible, pDevExt, cMillies);
|
---|
[17210] | 2820 | else
|
---|
[70873] | 2821 | rc = VbglR0HGCMInternalCall32(pInfo, cbInfo, fFlags, pSession->fRequestor,
|
---|
| 2822 | vgdrvHgcmAsyncWaitCallback, pDevExt, cMillies);
|
---|
[17196] | 2823 | }
|
---|
[17210] | 2824 | else
|
---|
| 2825 | #endif
|
---|
[17196] | 2826 | {
|
---|
[17210] | 2827 | if (fInterruptible)
|
---|
[70873] | 2828 | rc = VbglR0HGCMInternalCall(pInfo, cbInfo, fFlags, pSession->fRequestor,
|
---|
| 2829 | vgdrvHgcmAsyncWaitCallbackInterruptible, pDevExt, cMillies);
|
---|
[17210] | 2830 | else
|
---|
[70873] | 2831 | rc = VbglR0HGCMInternalCall(pInfo, cbInfo, fFlags, pSession->fRequestor,
|
---|
| 2832 | vgdrvHgcmAsyncWaitCallback, pDevExt, cMillies);
|
---|
[17196] | 2833 | }
|
---|
| 2834 | if (RT_SUCCESS(rc))
|
---|
| 2835 | {
|
---|
[68550] | 2836 | rc = pInfo->Hdr.rc;
|
---|
| 2837 | LogFlow(("VBOXGUEST_IOCTL_HGCM_CALL: result=%Rrc\n", rc));
|
---|
[17196] | 2838 | }
|
---|
[21524] | 2839 | else
|
---|
[26358] | 2840 | {
|
---|
[28516] | 2841 | if ( rc != VERR_INTERRUPTED
|
---|
| 2842 | && rc != VERR_TIMEOUT)
|
---|
[68550] | 2843 | LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CALL: %s Failed. rc=%Rrc (Hdr.rc=%Rrc).\n", f32bit ? "32" : "64", rc, pInfo->Hdr.rc));
|
---|
[26358] | 2844 | else
|
---|
[68550] | 2845 | Log(("VBOXGUEST_IOCTL_HGCM_CALL: %s Failed. rc=%Rrc (Hdr.rc=%Rrc).\n", f32bit ? "32" : "64", rc, pInfo->Hdr.rc));
|
---|
[26358] | 2846 | }
|
---|
[17196] | 2847 | return rc;
|
---|
| 2848 | }
|
---|
[54237] | 2849 |
|
---|
[68550] | 2850 |
|
---|
| 2851 | static int vgdrvIoCtl_HGCMCallWrapper(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCHGCMCALL pInfo,
|
---|
| 2852 | bool f32bit, bool fUserData, size_t cbData)
|
---|
| 2853 | {
|
---|
| 2854 | return vgdrvIoCtl_HGCMCallInner(pDevExt, pSession, pInfo, pInfo->cMsTimeout,
|
---|
| 2855 | pInfo->fInterruptible || pSession->R0Process != NIL_RTR0PROCESS,
|
---|
| 2856 | f32bit, fUserData, 0 /*cbExtra*/, cbData);
|
---|
| 2857 | }
|
---|
| 2858 |
|
---|
| 2859 |
|
---|
[75547] | 2860 | /**
|
---|
| 2861 | * Handles a fast HGCM call from another driver.
|
---|
| 2862 | *
|
---|
| 2863 | * The driver has provided a fully assembled HGCM call request and all we need
|
---|
| 2864 | * to do is send it to the host and do the wait processing.
|
---|
| 2865 | *
|
---|
| 2866 | * @returns VBox status code of the request submission part.
|
---|
| 2867 | * @param pDevExt The device extension.
|
---|
| 2868 | * @param pCallReq The call request.
|
---|
| 2869 | */
|
---|
| 2870 | static int vgdrvIoCtl_HGCMFastCall(PVBOXGUESTDEVEXT pDevExt, VBGLIOCIDCHGCMFASTCALL volatile *pCallReq)
|
---|
| 2871 | {
|
---|
| 2872 | VMMDevHGCMCall volatile *pHgcmCall = (VMMDevHGCMCall volatile *)(pCallReq + 1);
|
---|
| 2873 | int rc;
|
---|
| 2874 |
|
---|
| 2875 | /*
|
---|
| 2876 | * Check out the physical address.
|
---|
| 2877 | */
|
---|
| 2878 | Assert((pCallReq->GCPhysReq & PAGE_OFFSET_MASK) == ((uintptr_t)pHgcmCall & PAGE_OFFSET_MASK));
|
---|
[100267] | 2879 | AssertReturn(pCallReq->GCPhysReq == (uintptr_t)pCallReq->GCPhysReq, VERR_VBGL_INVALID_ADDR);
|
---|
[75547] | 2880 |
|
---|
| 2881 | AssertReturn(!pCallReq->fInterruptible, VERR_NOT_IMPLEMENTED);
|
---|
| 2882 |
|
---|
| 2883 | /*
|
---|
| 2884 | * Submit the request.
|
---|
| 2885 | */
|
---|
| 2886 | Log(("vgdrvIoCtl_HGCMFastCall -> host\n"));
|
---|
[100267] | 2887 | if (pDevExt->pMmioReq)
|
---|
| 2888 | *pDevExt->pMmioReq = (uintptr_t)pCallReq->GCPhysReq;
|
---|
| 2889 | else
|
---|
| 2890 | {
|
---|
| 2891 | #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
|
---|
| 2892 | ASMOutU32(pDevExt->IOPortBase + VMMDEV_PORT_OFF_REQUEST, (uint32_t)pCallReq->GCPhysReq);
|
---|
| 2893 | #elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
|
---|
| 2894 | AssertReleaseFailed(); /* Not possible on ARM. */
|
---|
| 2895 | return VERR_INVALID_STATE;
|
---|
| 2896 | #else
|
---|
| 2897 | # error "I have no memory of this architecture"
|
---|
| 2898 | #endif
|
---|
| 2899 | }
|
---|
[75547] | 2900 |
|
---|
| 2901 | /* Make the compiler aware that the host has changed memory. */
|
---|
| 2902 | ASMCompilerBarrier();
|
---|
| 2903 |
|
---|
[80041] | 2904 | rc = pHgcmCall->header.header.rc;
|
---|
[75547] | 2905 | Log(("vgdrvIoCtl_HGCMFastCall -> %Rrc (header rc=%Rrc)\n", rc, pHgcmCall->header.result));
|
---|
| 2906 |
|
---|
| 2907 | /*
|
---|
| 2908 | * The host is likely to engage in asynchronous execution of HGCM, unless it fails.
|
---|
| 2909 | */
|
---|
| 2910 | if (rc == VINF_HGCM_ASYNC_EXECUTE)
|
---|
| 2911 | {
|
---|
| 2912 | rc = vgdrvHgcmAsyncWaitCallbackWorker(&pHgcmCall->header, pDevExt, false /* fInterruptible */, RT_INDEFINITE_WAIT);
|
---|
| 2913 | if (pHgcmCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
|
---|
| 2914 | {
|
---|
| 2915 | Assert(!(pHgcmCall->header.fu32Flags & VBOX_HGCM_REQ_CANCELLED));
|
---|
| 2916 | rc = VINF_SUCCESS;
|
---|
| 2917 | }
|
---|
| 2918 | else
|
---|
| 2919 | {
|
---|
| 2920 | /*
|
---|
| 2921 | * Timeout and interrupt scenarios are messy and requires
|
---|
| 2922 | * cancelation, so implement later.
|
---|
| 2923 | */
|
---|
| 2924 | AssertReleaseMsgFailed(("rc=%Rrc\n", rc));
|
---|
| 2925 | }
|
---|
| 2926 | }
|
---|
| 2927 | else
|
---|
| 2928 | Assert((pHgcmCall->header.fu32Flags & VBOX_HGCM_REQ_DONE) || RT_FAILURE_NP(rc));
|
---|
| 2929 |
|
---|
| 2930 | Log(("vgdrvIoCtl_HGCMFastCall: rc=%Rrc result=%Rrc fu32Flags=%#x\n", rc, pHgcmCall->header.result, pHgcmCall->header.fu32Flags));
|
---|
| 2931 | return rc;
|
---|
| 2932 |
|
---|
| 2933 | }
|
---|
| 2934 |
|
---|
[50803] | 2935 | #endif /* VBOX_WITH_HGCM */
|
---|
[17196] | 2936 |
|
---|
[3657] | 2937 | /**
|
---|
[68550] | 2938 | * Handle VBGL_IOCTL_CHECK_BALLOON from R3.
|
---|
[26934] | 2939 | *
|
---|
[27967] | 2940 | * Ask the host for the size of the balloon and try to set it accordingly. If
|
---|
| 2941 | * this approach fails because it's not supported, return with fHandleInR3 set
|
---|
| 2942 | * and let the user land supply memory we can lock via the other ioctl.
|
---|
[27106] | 2943 | *
|
---|
[26934] | 2944 | * @returns VBox status code.
|
---|
[27106] | 2945 | *
|
---|
| 2946 | * @param pDevExt The device extension.
|
---|
[27118] | 2947 | * @param pSession The session.
|
---|
[27106] | 2948 | * @param pInfo The output buffer.
|
---|
[26934] | 2949 | */
|
---|
[68550] | 2950 | static int vgdrvIoCtl_CheckMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCCHECKBALLOON pInfo)
|
---|
[26934] | 2951 | {
|
---|
[54237] | 2952 | VMMDevGetMemBalloonChangeRequest *pReq;
|
---|
| 2953 | int rc;
|
---|
[27118] | 2954 |
|
---|
[68550] | 2955 | LogFlow(("VBGL_IOCTL_CHECK_BALLOON:\n"));
|
---|
[54237] | 2956 | rc = RTSemFastMutexRequest(pDevExt->MemBalloon.hMtx);
|
---|
[27967] | 2957 | AssertRCReturn(rc, rc);
|
---|
[27118] | 2958 |
|
---|
[27967] | 2959 | /*
|
---|
| 2960 | * The first user trying to query/change the balloon becomes the
|
---|
[58053] | 2961 | * owner and owns it until the session is closed (vgdrvCloseMemBalloon).
|
---|
[27967] | 2962 | */
|
---|
| 2963 | if ( pDevExt->MemBalloon.pOwner != pSession
|
---|
| 2964 | && pDevExt->MemBalloon.pOwner == NULL)
|
---|
| 2965 | pDevExt->MemBalloon.pOwner = pSession;
|
---|
[26934] | 2966 |
|
---|
[27967] | 2967 | if (pDevExt->MemBalloon.pOwner == pSession)
|
---|
[26934] | 2968 | {
|
---|
[70873] | 2969 | /*
|
---|
| 2970 | * This is a response to that event. Setting this bit means that
|
---|
| 2971 | * we request the value from the host and change the guest memory
|
---|
| 2972 | * balloon according to this value.
|
---|
| 2973 | */
|
---|
[68654] | 2974 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevGetMemBalloonChangeRequest), VMMDevReq_GetMemBalloonChangeRequest);
|
---|
[27967] | 2975 | if (RT_SUCCESS(rc))
|
---|
| 2976 | {
|
---|
[70873] | 2977 | pReq->header.fRequestor = pSession->fRequestor;
|
---|
[27967] | 2978 | pReq->eventAck = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
|
---|
[68654] | 2979 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[27967] | 2980 | if (RT_SUCCESS(rc))
|
---|
| 2981 | {
|
---|
| 2982 | Assert(pDevExt->MemBalloon.cMaxChunks == pReq->cPhysMemChunks || pDevExt->MemBalloon.cMaxChunks == 0);
|
---|
| 2983 | pDevExt->MemBalloon.cMaxChunks = pReq->cPhysMemChunks;
|
---|
[26934] | 2984 |
|
---|
[68550] | 2985 | pInfo->u.Out.cBalloonChunks = pReq->cBalloonChunks;
|
---|
| 2986 | pInfo->u.Out.fHandleInR3 = false;
|
---|
| 2987 | pInfo->u.Out.afPadding[0] = false;
|
---|
| 2988 | pInfo->u.Out.afPadding[1] = false;
|
---|
| 2989 | pInfo->u.Out.afPadding[2] = false;
|
---|
[26934] | 2990 |
|
---|
[68550] | 2991 | rc = vgdrvSetBalloonSizeKernel(pDevExt, pReq->cBalloonChunks, &pInfo->u.Out.fHandleInR3);
|
---|
[27967] | 2992 | /* Ignore various out of memory failures. */
|
---|
| 2993 | if ( rc == VERR_NO_MEMORY
|
---|
| 2994 | || rc == VERR_NO_PHYS_MEMORY
|
---|
| 2995 | || rc == VERR_NO_CONT_MEMORY)
|
---|
| 2996 | rc = VINF_SUCCESS;
|
---|
| 2997 | }
|
---|
| 2998 | else
|
---|
[68654] | 2999 | LogRel(("VBGL_IOCTL_CHECK_BALLOON: VbglR0GRPerform failed. rc=%Rrc\n", rc));
|
---|
| 3000 | VbglR0GRFree(&pReq->header);
|
---|
[27967] | 3001 | }
|
---|
[27023] | 3002 | }
|
---|
[27967] | 3003 | else
|
---|
| 3004 | rc = VERR_PERMISSION_DENIED;
|
---|
[27023] | 3005 |
|
---|
[27967] | 3006 | RTSemFastMutexRelease(pDevExt->MemBalloon.hMtx);
|
---|
[68550] | 3007 | LogFlow(("VBGL_IOCTL_CHECK_BALLOON returns %Rrc\n", rc));
|
---|
[26934] | 3008 | return rc;
|
---|
| 3009 | }
|
---|
| 3010 |
|
---|
[26999] | 3011 |
|
---|
[26934] | 3012 | /**
|
---|
[27106] | 3013 | * Handle a request for changing the memory balloon.
|
---|
[26999] | 3014 | *
|
---|
[27106] | 3015 | * @returns VBox status code.
|
---|
| 3016 | *
|
---|
| 3017 | * @param pDevExt The device extention.
|
---|
| 3018 | * @param pSession The session.
|
---|
| 3019 | * @param pInfo The change request structure (input).
|
---|
[26999] | 3020 | */
|
---|
[68550] | 3021 | static int vgdrvIoCtl_ChangeMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCCHANGEBALLOON pInfo)
|
---|
[26999] | 3022 | {
|
---|
[54237] | 3023 | int rc;
|
---|
[68550] | 3024 | LogFlow(("VBGL_IOCTL_CHANGE_BALLOON: fInflate=%RTbool u64ChunkAddr=%p\n", pInfo->u.In.fInflate, pInfo->u.In.pvChunk));
|
---|
| 3025 | if ( pInfo->u.In.abPadding[0]
|
---|
| 3026 | || pInfo->u.In.abPadding[1]
|
---|
| 3027 | || pInfo->u.In.abPadding[2]
|
---|
| 3028 | || pInfo->u.In.abPadding[3]
|
---|
| 3029 | || pInfo->u.In.abPadding[4]
|
---|
| 3030 | || pInfo->u.In.abPadding[5]
|
---|
| 3031 | || pInfo->u.In.abPadding[6]
|
---|
| 3032 | #if ARCH_BITS == 32
|
---|
| 3033 | || pInfo->u.In.abPadding[7]
|
---|
| 3034 | || pInfo->u.In.abPadding[8]
|
---|
| 3035 | || pInfo->u.In.abPadding[9]
|
---|
| 3036 | #endif
|
---|
| 3037 | )
|
---|
| 3038 | {
|
---|
| 3039 | Log(("VBGL_IOCTL_CHANGE_BALLOON: Padding isn't all zero: %.*Rhxs\n", sizeof(pInfo->u.In.abPadding), pInfo->u.In.abPadding));
|
---|
| 3040 | return VERR_INVALID_PARAMETER;
|
---|
| 3041 | }
|
---|
[54237] | 3042 |
|
---|
| 3043 | rc = RTSemFastMutexRequest(pDevExt->MemBalloon.hMtx);
|
---|
[27967] | 3044 | AssertRCReturn(rc, rc);
|
---|
[27118] | 3045 |
|
---|
[27967] | 3046 | if (!pDevExt->MemBalloon.fUseKernelAPI)
|
---|
| 3047 | {
|
---|
| 3048 | /*
|
---|
| 3049 | * The first user trying to query/change the balloon becomes the
|
---|
[58053] | 3050 | * owner and owns it until the session is closed (vgdrvCloseMemBalloon).
|
---|
[27967] | 3051 | */
|
---|
| 3052 | if ( pDevExt->MemBalloon.pOwner != pSession
|
---|
| 3053 | && pDevExt->MemBalloon.pOwner == NULL)
|
---|
| 3054 | pDevExt->MemBalloon.pOwner = pSession;
|
---|
[27118] | 3055 |
|
---|
[27967] | 3056 | if (pDevExt->MemBalloon.pOwner == pSession)
|
---|
[68550] | 3057 | rc = vgdrvSetBalloonSizeFromUser(pDevExt, pSession, pInfo->u.In.pvChunk, pInfo->u.In.fInflate != false);
|
---|
[27967] | 3058 | else
|
---|
| 3059 | rc = VERR_PERMISSION_DENIED;
|
---|
| 3060 | }
|
---|
| 3061 | else
|
---|
| 3062 | rc = VERR_PERMISSION_DENIED;
|
---|
[27118] | 3063 |
|
---|
[27967] | 3064 | RTSemFastMutexRelease(pDevExt->MemBalloon.hMtx);
|
---|
[26999] | 3065 | return rc;
|
---|
| 3066 | }
|
---|
| 3067 |
|
---|
| 3068 |
|
---|
[32574] | 3069 | /**
|
---|
| 3070 | * Handle a request for writing a core dump of the guest on the host.
|
---|
| 3071 | *
|
---|
| 3072 | * @returns VBox status code.
|
---|
| 3073 | *
|
---|
[70873] | 3074 | * @param pDevExt The device extension.
|
---|
| 3075 | * @param pSession The session.
|
---|
| 3076 | * @param pInfo The output buffer.
|
---|
[32574] | 3077 | */
|
---|
[70873] | 3078 | static int vgdrvIoCtl_WriteCoreDump(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCWRITECOREDUMP pInfo)
|
---|
[32574] | 3079 | {
|
---|
| 3080 | VMMDevReqWriteCoreDump *pReq = NULL;
|
---|
[54237] | 3081 | int rc;
|
---|
[54615] | 3082 | LogFlow(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP\n"));
|
---|
[62853] | 3083 | RT_NOREF1(pDevExt);
|
---|
[54237] | 3084 |
|
---|
[68654] | 3085 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_WriteCoreDump);
|
---|
[54615] | 3086 | if (RT_SUCCESS(rc))
|
---|
[32574] | 3087 | {
|
---|
[70873] | 3088 | pReq->header.fRequestor = pSession->fRequestor;
|
---|
[68550] | 3089 | pReq->fFlags = pInfo->u.In.fFlags;
|
---|
[68654] | 3090 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[54615] | 3091 | if (RT_FAILURE(rc))
|
---|
[68654] | 3092 | Log(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP: VbglR0GRPerform failed, rc=%Rrc!\n", rc));
|
---|
[54615] | 3093 |
|
---|
[68654] | 3094 | VbglR0GRFree(&pReq->header);
|
---|
[54615] | 3095 | }
|
---|
| 3096 | else
|
---|
| 3097 | Log(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
|
---|
[54237] | 3098 | sizeof(*pReq), sizeof(*pReq), rc));
|
---|
[32574] | 3099 | return rc;
|
---|
| 3100 | }
|
---|
| 3101 |
|
---|
| 3102 |
|
---|
[26999] | 3103 | /**
|
---|
[6436] | 3104 | * Guest backdoor logging.
|
---|
| 3105 | *
|
---|
| 3106 | * @returns VBox status code.
|
---|
| 3107 | *
|
---|
[40198] | 3108 | * @param pDevExt The device extension.
|
---|
[6436] | 3109 | * @param pch The log message (need not be NULL terminated).
|
---|
| 3110 | * @param cbData Size of the buffer.
|
---|
[58089] | 3111 | * @param fUserSession Copy of VBOXGUESTSESSION::fUserSession for the
|
---|
| 3112 | * call. True normal user, false root user.
|
---|
[6436] | 3113 | */
|
---|
[68550] | 3114 | static int vgdrvIoCtl_Log(PVBOXGUESTDEVEXT pDevExt, const char *pch, size_t cbData, bool fUserSession)
|
---|
[6436] | 3115 | {
|
---|
[40198] | 3116 | if (pDevExt->fLoggingEnabled)
|
---|
| 3117 | RTLogBackdoorPrintf("%.*s", cbData, pch);
|
---|
[52701] | 3118 | else if (!fUserSession)
|
---|
| 3119 | LogRel(("%.*s", cbData, pch));
|
---|
[40198] | 3120 | else
|
---|
| 3121 | Log(("%.*s", cbData, pch));
|
---|
[6436] | 3122 | return VINF_SUCCESS;
|
---|
| 3123 | }
|
---|
| 3124 |
|
---|
[54237] | 3125 |
|
---|
[54593] | 3126 | /** @name Guest Capabilities, Mouse Status and Event Filter
|
---|
| 3127 | * @{
|
---|
| 3128 | */
|
---|
| 3129 |
|
---|
| 3130 | /**
|
---|
[54606] | 3131 | * Clears a bit usage tracker (init time).
|
---|
[54593] | 3132 | *
|
---|
[54606] | 3133 | * @param pTracker The tracker to clear.
|
---|
| 3134 | */
|
---|
[58053] | 3135 | static void vgdrvBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker)
|
---|
[54606] | 3136 | {
|
---|
| 3137 | uint32_t iBit;
|
---|
| 3138 | AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
|
---|
| 3139 |
|
---|
| 3140 | for (iBit = 0; iBit < 32; iBit++)
|
---|
| 3141 | pTracker->acPerBitUsage[iBit] = 0;
|
---|
| 3142 | pTracker->fMask = 0;
|
---|
| 3143 | }
|
---|
| 3144 |
|
---|
| 3145 |
|
---|
| 3146 | #ifdef VBOX_STRICT
|
---|
| 3147 | /**
|
---|
| 3148 | * Checks that pTracker->fMask is correct and that the usage values are within
|
---|
| 3149 | * the valid range.
|
---|
[54593] | 3150 | *
|
---|
[54606] | 3151 | * @param pTracker The tracker.
|
---|
| 3152 | * @param cMax Max valid usage value.
|
---|
| 3153 | * @param pszWhat Identifies the tracker in assertions.
|
---|
[54593] | 3154 | */
|
---|
[58053] | 3155 | static void vgdrvBitUsageTrackerCheckMask(PCVBOXGUESTBITUSAGETRACER pTracker, uint32_t cMax, const char *pszWhat)
|
---|
[54593] | 3156 | {
|
---|
[54606] | 3157 | uint32_t fMask = 0;
|
---|
| 3158 | uint32_t iBit;
|
---|
| 3159 | AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
|
---|
[54593] | 3160 |
|
---|
[54606] | 3161 | for (iBit = 0; iBit < 32; iBit++)
|
---|
| 3162 | if (pTracker->acPerBitUsage[iBit])
|
---|
| 3163 | {
|
---|
| 3164 | fMask |= RT_BIT_32(iBit);
|
---|
| 3165 | AssertMsg(pTracker->acPerBitUsage[iBit] <= cMax,
|
---|
| 3166 | ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
|
---|
| 3167 | }
|
---|
| 3168 |
|
---|
| 3169 | AssertMsg(fMask == pTracker->fMask, ("%s: %#x vs %#x\n", pszWhat, fMask, pTracker->fMask));
|
---|
| 3170 | }
|
---|
| 3171 | #endif
|
---|
| 3172 |
|
---|
| 3173 |
|
---|
| 3174 | /**
|
---|
| 3175 | * Applies a change to the bit usage tracker.
|
---|
| 3176 | *
|
---|
| 3177 | *
|
---|
| 3178 | * @returns true if the mask changed, false if not.
|
---|
| 3179 | * @param pTracker The bit usage tracker.
|
---|
| 3180 | * @param fChanged The bits to change.
|
---|
| 3181 | * @param fPrevious The previous value of the bits.
|
---|
| 3182 | * @param cMax The max valid usage value for assertions.
|
---|
| 3183 | * @param pszWhat Identifies the tracker in assertions.
|
---|
| 3184 | */
|
---|
[58053] | 3185 | static bool vgdrvBitUsageTrackerChange(PVBOXGUESTBITUSAGETRACER pTracker, uint32_t fChanged, uint32_t fPrevious,
|
---|
| 3186 | uint32_t cMax, const char *pszWhat)
|
---|
[54606] | 3187 | {
|
---|
[54613] | 3188 | bool fGlobalChange = false;
|
---|
[54606] | 3189 | AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
|
---|
| 3190 |
|
---|
[54613] | 3191 | while (fChanged)
|
---|
[54606] | 3192 | {
|
---|
[54613] | 3193 | uint32_t const iBit = ASMBitFirstSetU32(fChanged) - 1;
|
---|
[54606] | 3194 | uint32_t const fBitMask = RT_BIT_32(iBit);
|
---|
[54613] | 3195 | Assert(iBit < 32); Assert(fBitMask & fChanged);
|
---|
| 3196 |
|
---|
| 3197 | if (fBitMask & fPrevious)
|
---|
[54606] | 3198 | {
|
---|
[54613] | 3199 | pTracker->acPerBitUsage[iBit] -= 1;
|
---|
| 3200 | AssertMsg(pTracker->acPerBitUsage[iBit] <= cMax,
|
---|
| 3201 | ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
|
---|
| 3202 | if (pTracker->acPerBitUsage[iBit] == 0)
|
---|
[54606] | 3203 | {
|
---|
[54613] | 3204 | fGlobalChange = true;
|
---|
| 3205 | pTracker->fMask &= ~fBitMask;
|
---|
[54606] | 3206 | }
|
---|
[54613] | 3207 | }
|
---|
| 3208 | else
|
---|
| 3209 | {
|
---|
| 3210 | pTracker->acPerBitUsage[iBit] += 1;
|
---|
| 3211 | AssertMsg(pTracker->acPerBitUsage[iBit] > 0 && pTracker->acPerBitUsage[iBit] <= cMax,
|
---|
| 3212 | ("pTracker->acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
|
---|
| 3213 | if (pTracker->acPerBitUsage[iBit] == 1)
|
---|
[54606] | 3214 | {
|
---|
[54613] | 3215 | fGlobalChange = true;
|
---|
| 3216 | pTracker->fMask |= fBitMask;
|
---|
[54606] | 3217 | }
|
---|
| 3218 | }
|
---|
[54613] | 3219 |
|
---|
| 3220 | fChanged &= ~fBitMask;
|
---|
[54606] | 3221 | }
|
---|
| 3222 |
|
---|
| 3223 | #ifdef VBOX_STRICT
|
---|
[58053] | 3224 | vgdrvBitUsageTrackerCheckMask(pTracker, cMax, pszWhat);
|
---|
[54606] | 3225 | #endif
|
---|
| 3226 | NOREF(pszWhat); NOREF(cMax);
|
---|
| 3227 | return fGlobalChange;
|
---|
| 3228 | }
|
---|
| 3229 |
|
---|
| 3230 |
|
---|
| 3231 | /**
|
---|
| 3232 | * Init and termination worker for resetting the (host) event filter on the host
|
---|
| 3233 | *
|
---|
| 3234 | * @returns VBox status code.
|
---|
| 3235 | * @param pDevExt The device extension.
|
---|
| 3236 | * @param fFixedEvents Fixed events (init time).
|
---|
| 3237 | */
|
---|
[58053] | 3238 | static int vgdrvResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt, uint32_t fFixedEvents)
|
---|
[54606] | 3239 | {
|
---|
| 3240 | VMMDevCtlGuestFilterMask *pReq;
|
---|
[68654] | 3241 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
|
---|
[54606] | 3242 | if (RT_SUCCESS(rc))
|
---|
| 3243 | {
|
---|
| 3244 | pReq->u32NotMask = UINT32_MAX & ~fFixedEvents;
|
---|
| 3245 | pReq->u32OrMask = fFixedEvents;
|
---|
[68654] | 3246 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[54606] | 3247 | if (RT_FAILURE(rc))
|
---|
| 3248 | LogRelFunc(("failed with rc=%Rrc\n", rc));
|
---|
[68654] | 3249 | VbglR0GRFree(&pReq->header);
|
---|
[54606] | 3250 | }
|
---|
[62853] | 3251 | RT_NOREF1(pDevExt);
|
---|
[54593] | 3252 | return rc;
|
---|
| 3253 | }
|
---|
| 3254 |
|
---|
| 3255 |
|
---|
| 3256 | /**
|
---|
[54606] | 3257 | * Changes the event filter mask for the given session.
|
---|
[54593] | 3258 | *
|
---|
[68550] | 3259 | * This is called in response to VBGL_IOCTL_CHANGE_FILTER_MASK as well as to do
|
---|
| 3260 | * session cleanup.
|
---|
[54593] | 3261 | *
|
---|
| 3262 | * @returns VBox status code.
|
---|
[54606] | 3263 | * @param pDevExt The device extension.
|
---|
| 3264 | * @param pSession The session.
|
---|
| 3265 | * @param fOrMask The events to add.
|
---|
| 3266 | * @param fNotMask The events to remove.
|
---|
| 3267 | * @param fSessionTermination Set if we're called by the session cleanup code.
|
---|
| 3268 | * This tweaks the error handling so we perform
|
---|
| 3269 | * proper session cleanup even if the host
|
---|
| 3270 | * misbehaves.
|
---|
| 3271 | *
|
---|
| 3272 | * @remarks Takes the session spinlock.
|
---|
[54593] | 3273 | */
|
---|
[58053] | 3274 | static int vgdrvSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
| 3275 | uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
|
---|
[54593] | 3276 | {
|
---|
[54606] | 3277 | VMMDevCtlGuestFilterMask *pReq;
|
---|
| 3278 | uint32_t fChanged;
|
---|
| 3279 | uint32_t fPrevious;
|
---|
| 3280 | int rc;
|
---|
[54593] | 3281 |
|
---|
[54606] | 3282 | /*
|
---|
| 3283 | * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
|
---|
| 3284 | */
|
---|
[68654] | 3285 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
|
---|
[54606] | 3286 | if (RT_SUCCESS(rc))
|
---|
| 3287 | { /* nothing */ }
|
---|
| 3288 | else if (!fSessionTermination)
|
---|
| 3289 | {
|
---|
[68654] | 3290 | LogRel(("vgdrvSetSessionFilterMask: VbglR0GRAlloc failure: %Rrc\n", rc));
|
---|
[54606] | 3291 | return rc;
|
---|
| 3292 | }
|
---|
| 3293 | else
|
---|
| 3294 | pReq = NULL; /* Ignore failure, we must do session cleanup. */
|
---|
| 3295 |
|
---|
| 3296 |
|
---|
| 3297 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
| 3298 |
|
---|
| 3299 | /*
|
---|
| 3300 | * Apply the changes to the session mask.
|
---|
| 3301 | */
|
---|
| 3302 | fPrevious = pSession->fEventFilter;
|
---|
| 3303 | pSession->fEventFilter |= fOrMask;
|
---|
[54721] | 3304 | pSession->fEventFilter &= ~fNotMask;
|
---|
[54606] | 3305 |
|
---|
| 3306 | /*
|
---|
| 3307 | * If anything actually changed, update the global usage counters.
|
---|
| 3308 | */
|
---|
| 3309 | fChanged = fPrevious ^ pSession->fEventFilter;
|
---|
[68550] | 3310 | LogFlow(("vgdrvSetSessionEventFilter: Session->fEventFilter: %#x -> %#x (changed %#x)\n",
|
---|
| 3311 | fPrevious, pSession->fEventFilter, fChanged));
|
---|
[54606] | 3312 | if (fChanged)
|
---|
| 3313 | {
|
---|
[58053] | 3314 | bool fGlobalChange = vgdrvBitUsageTrackerChange(&pDevExt->EventFilterTracker, fChanged, fPrevious,
|
---|
| 3315 | pDevExt->cSessions, "EventFilterTracker");
|
---|
[54606] | 3316 |
|
---|
| 3317 | /*
|
---|
| 3318 | * If there are global changes, update the event filter on the host.
|
---|
| 3319 | */
|
---|
| 3320 | if (fGlobalChange || pDevExt->fEventFilterHost == UINT32_MAX)
|
---|
| 3321 | {
|
---|
| 3322 | Assert(pReq || fSessionTermination);
|
---|
| 3323 | if (pReq)
|
---|
| 3324 | {
|
---|
| 3325 | pReq->u32OrMask = pDevExt->fFixedEvents | pDevExt->EventFilterTracker.fMask;
|
---|
| 3326 | if (pReq->u32OrMask == pDevExt->fEventFilterHost)
|
---|
| 3327 | rc = VINF_SUCCESS;
|
---|
| 3328 | else
|
---|
| 3329 | {
|
---|
| 3330 | pDevExt->fEventFilterHost = pReq->u32OrMask;
|
---|
| 3331 | pReq->u32NotMask = ~pReq->u32OrMask;
|
---|
[68654] | 3332 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[54606] | 3333 | if (RT_FAILURE(rc))
|
---|
| 3334 | {
|
---|
| 3335 | /*
|
---|
| 3336 | * Failed, roll back (unless it's session termination time).
|
---|
| 3337 | */
|
---|
| 3338 | pDevExt->fEventFilterHost = UINT32_MAX;
|
---|
| 3339 | if (!fSessionTermination)
|
---|
| 3340 | {
|
---|
[58053] | 3341 | vgdrvBitUsageTrackerChange(&pDevExt->EventFilterTracker, fChanged, pSession->fEventFilter,
|
---|
| 3342 | pDevExt->cSessions, "EventFilterTracker");
|
---|
[54606] | 3343 | pSession->fEventFilter = fPrevious;
|
---|
| 3344 | }
|
---|
| 3345 | }
|
---|
| 3346 | }
|
---|
| 3347 | }
|
---|
| 3348 | else
|
---|
| 3349 | rc = VINF_SUCCESS;
|
---|
| 3350 | }
|
---|
| 3351 | }
|
---|
| 3352 |
|
---|
| 3353 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
| 3354 | if (pReq)
|
---|
[68654] | 3355 | VbglR0GRFree(&pReq->header);
|
---|
[54593] | 3356 | return rc;
|
---|
| 3357 | }
|
---|
| 3358 |
|
---|
| 3359 |
|
---|
[54606] | 3360 | /**
|
---|
[68550] | 3361 | * Handle VBGL_IOCTL_CHANGE_FILTER_MASK.
|
---|
[54606] | 3362 | *
|
---|
| 3363 | * @returns VBox status code.
|
---|
| 3364 | *
|
---|
| 3365 | * @param pDevExt The device extension.
|
---|
| 3366 | * @param pSession The session.
|
---|
| 3367 | * @param pInfo The request.
|
---|
| 3368 | */
|
---|
[68550] | 3369 | static int vgdrvIoCtl_ChangeFilterMask(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCCHANGEFILTERMASK pInfo)
|
---|
[54593] | 3370 | {
|
---|
[68550] | 3371 | LogFlow(("VBGL_IOCTL_CHANGE_FILTER_MASK: or=%#x not=%#x\n", pInfo->u.In.fOrMask, pInfo->u.In.fNotMask));
|
---|
[54593] | 3372 |
|
---|
[68550] | 3373 | if ((pInfo->u.In.fOrMask | pInfo->u.In.fNotMask) & ~VMMDEV_EVENT_VALID_EVENT_MASK)
|
---|
[54593] | 3374 | {
|
---|
[68550] | 3375 | Log(("VBGL_IOCTL_CHANGE_FILTER_MASK: or=%#x not=%#x: Invalid masks!\n", pInfo->u.In.fOrMask, pInfo->u.In.fNotMask));
|
---|
[54606] | 3376 | return VERR_INVALID_PARAMETER;
|
---|
[54593] | 3377 | }
|
---|
[54606] | 3378 |
|
---|
[68550] | 3379 | return vgdrvSetSessionEventFilter(pDevExt, pSession, pInfo->u.In.fOrMask, pInfo->u.In.fNotMask, false /*fSessionTermination*/);
|
---|
[54606] | 3380 | }
|
---|
| 3381 |
|
---|
| 3382 |
|
---|
| 3383 | /**
|
---|
| 3384 | * Init and termination worker for set mouse feature status to zero on the host.
|
---|
| 3385 | *
|
---|
| 3386 | * @returns VBox status code.
|
---|
| 3387 | * @param pDevExt The device extension.
|
---|
| 3388 | */
|
---|
[58053] | 3389 | static int vgdrvResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt)
|
---|
[54606] | 3390 | {
|
---|
| 3391 | VMMDevReqMouseStatus *pReq;
|
---|
[68654] | 3392 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetMouseStatus);
|
---|
[54606] | 3393 | if (RT_SUCCESS(rc))
|
---|
| 3394 | {
|
---|
| 3395 | pReq->mouseFeatures = 0;
|
---|
| 3396 | pReq->pointerXPos = 0;
|
---|
| 3397 | pReq->pointerYPos = 0;
|
---|
[68654] | 3398 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[54606] | 3399 | if (RT_FAILURE(rc))
|
---|
| 3400 | LogRelFunc(("failed with rc=%Rrc\n", rc));
|
---|
[68654] | 3401 | VbglR0GRFree(&pReq->header);
|
---|
[54606] | 3402 | }
|
---|
[62853] | 3403 | RT_NOREF1(pDevExt);
|
---|
[54593] | 3404 | return rc;
|
---|
| 3405 | }
|
---|
| 3406 |
|
---|
| 3407 |
|
---|
| 3408 | /**
|
---|
[54606] | 3409 | * Changes the mouse status mask for the given session.
|
---|
[54593] | 3410 | *
|
---|
[54606] | 3411 | * This is called in response to VBOXGUEST_IOCTL_SET_MOUSE_STATUS as well as to
|
---|
| 3412 | * do session cleanup.
|
---|
[54593] | 3413 | *
|
---|
[54606] | 3414 | * @returns VBox status code.
|
---|
| 3415 | * @param pDevExt The device extension.
|
---|
| 3416 | * @param pSession The session.
|
---|
| 3417 | * @param fOrMask The status flags to add.
|
---|
| 3418 | * @param fNotMask The status flags to remove.
|
---|
| 3419 | * @param fSessionTermination Set if we're called by the session cleanup code.
|
---|
| 3420 | * This tweaks the error handling so we perform
|
---|
| 3421 | * proper session cleanup even if the host
|
---|
| 3422 | * misbehaves.
|
---|
| 3423 | *
|
---|
| 3424 | * @remarks Takes the session spinlock.
|
---|
[54593] | 3425 | */
|
---|
[58053] | 3426 | static int vgdrvSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
| 3427 | uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
|
---|
[54593] | 3428 | {
|
---|
[54606] | 3429 | VMMDevReqMouseStatus *pReq;
|
---|
| 3430 | uint32_t fChanged;
|
---|
| 3431 | uint32_t fPrevious;
|
---|
| 3432 | int rc;
|
---|
[54593] | 3433 |
|
---|
[54606] | 3434 | /*
|
---|
| 3435 | * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
|
---|
| 3436 | */
|
---|
[68654] | 3437 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetMouseStatus);
|
---|
[54593] | 3438 | if (RT_SUCCESS(rc))
|
---|
[70873] | 3439 | {
|
---|
| 3440 | if (!fSessionTermination)
|
---|
| 3441 | pReq->header.fRequestor = pSession->fRequestor;
|
---|
| 3442 | }
|
---|
[54606] | 3443 | else if (!fSessionTermination)
|
---|
[54593] | 3444 | {
|
---|
[68654] | 3445 | LogRel(("vgdrvSetSessionMouseStatus: VbglR0GRAlloc failure: %Rrc\n", rc));
|
---|
[54606] | 3446 | return rc;
|
---|
| 3447 | }
|
---|
| 3448 | else
|
---|
| 3449 | pReq = NULL; /* Ignore failure, we must do session cleanup. */
|
---|
| 3450 |
|
---|
| 3451 |
|
---|
| 3452 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
| 3453 |
|
---|
| 3454 | /*
|
---|
| 3455 | * Apply the changes to the session mask.
|
---|
| 3456 | */
|
---|
| 3457 | fPrevious = pSession->fMouseStatus;
|
---|
| 3458 | pSession->fMouseStatus |= fOrMask;
|
---|
[54721] | 3459 | pSession->fMouseStatus &= ~fNotMask;
|
---|
[54606] | 3460 |
|
---|
| 3461 | /*
|
---|
| 3462 | * If anything actually changed, update the global usage counters.
|
---|
| 3463 | */
|
---|
| 3464 | fChanged = fPrevious ^ pSession->fMouseStatus;
|
---|
| 3465 | if (fChanged)
|
---|
| 3466 | {
|
---|
[58053] | 3467 | bool fGlobalChange = vgdrvBitUsageTrackerChange(&pDevExt->MouseStatusTracker, fChanged, fPrevious,
|
---|
| 3468 | pDevExt->cSessions, "MouseStatusTracker");
|
---|
[54606] | 3469 |
|
---|
| 3470 | /*
|
---|
| 3471 | * If there are global changes, update the event filter on the host.
|
---|
| 3472 | */
|
---|
| 3473 | if (fGlobalChange || pDevExt->fMouseStatusHost == UINT32_MAX)
|
---|
[54593] | 3474 | {
|
---|
[54606] | 3475 | Assert(pReq || fSessionTermination);
|
---|
| 3476 | if (pReq)
|
---|
| 3477 | {
|
---|
[54612] | 3478 | pReq->mouseFeatures = pDevExt->MouseStatusTracker.fMask;
|
---|
[54606] | 3479 | if (pReq->mouseFeatures == pDevExt->fMouseStatusHost)
|
---|
| 3480 | rc = VINF_SUCCESS;
|
---|
| 3481 | else
|
---|
| 3482 | {
|
---|
| 3483 | pDevExt->fMouseStatusHost = pReq->mouseFeatures;
|
---|
| 3484 | pReq->pointerXPos = 0;
|
---|
| 3485 | pReq->pointerYPos = 0;
|
---|
[68654] | 3486 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[54606] | 3487 | if (RT_FAILURE(rc))
|
---|
| 3488 | {
|
---|
| 3489 | /*
|
---|
| 3490 | * Failed, roll back (unless it's session termination time).
|
---|
| 3491 | */
|
---|
| 3492 | pDevExt->fMouseStatusHost = UINT32_MAX;
|
---|
| 3493 | if (!fSessionTermination)
|
---|
| 3494 | {
|
---|
[58053] | 3495 | vgdrvBitUsageTrackerChange(&pDevExt->MouseStatusTracker, fChanged, pSession->fMouseStatus,
|
---|
| 3496 | pDevExt->cSessions, "MouseStatusTracker");
|
---|
[54606] | 3497 | pSession->fMouseStatus = fPrevious;
|
---|
| 3498 | }
|
---|
| 3499 | }
|
---|
| 3500 | }
|
---|
| 3501 | }
|
---|
| 3502 | else
|
---|
| 3503 | rc = VINF_SUCCESS;
|
---|
[54593] | 3504 | }
|
---|
| 3505 | }
|
---|
[54601] | 3506 |
|
---|
[54606] | 3507 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
| 3508 | if (pReq)
|
---|
[68654] | 3509 | VbglR0GRFree(&pReq->header);
|
---|
[54593] | 3510 | return rc;
|
---|
| 3511 | }
|
---|
| 3512 |
|
---|
[54601] | 3513 |
|
---|
| 3514 | /**
|
---|
[54606] | 3515 | * Sets the mouse status features for this session and updates them globally.
|
---|
[54601] | 3516 | *
|
---|
[54606] | 3517 | * @returns VBox status code.
|
---|
| 3518 | *
|
---|
| 3519 | * @param pDevExt The device extention.
|
---|
| 3520 | * @param pSession The session.
|
---|
| 3521 | * @param fFeatures New bitmap of enabled features.
|
---|
| 3522 | */
|
---|
[58053] | 3523 | static int vgdrvIoCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fFeatures)
|
---|
[54606] | 3524 | {
|
---|
[68550] | 3525 | LogFlow(("VBGL_IOCTL_SET_MOUSE_STATUS: features=%#x\n", fFeatures));
|
---|
[54606] | 3526 |
|
---|
| 3527 | if (fFeatures & ~VMMDEV_MOUSE_GUEST_MASK)
|
---|
| 3528 | return VERR_INVALID_PARAMETER;
|
---|
| 3529 |
|
---|
[58053] | 3530 | return vgdrvSetSessionMouseStatus(pDevExt, pSession, fFeatures, ~fFeatures, false /*fSessionTermination*/);
|
---|
[54606] | 3531 | }
|
---|
| 3532 |
|
---|
| 3533 |
|
---|
| 3534 | /**
|
---|
| 3535 | * Return the mask of VMM device events that this session is allowed to see (wrt
|
---|
| 3536 | * to "acquire" mode guest capabilities).
|
---|
| 3537 | *
|
---|
[54601] | 3538 | * The events associated with guest capabilities in "acquire" mode will be
|
---|
| 3539 | * restricted to sessions which has acquired the respective capabilities.
|
---|
| 3540 | * If someone else tries to wait for acquired events, they won't be woken up
|
---|
| 3541 | * when the event becomes pending. Should some other thread in the session
|
---|
| 3542 | * acquire the capability while the corresponding event is pending, the waiting
|
---|
| 3543 | * thread will woken up.
|
---|
| 3544 | *
|
---|
| 3545 | * @returns Mask of events valid for the given session.
|
---|
| 3546 | * @param pDevExt The device extension.
|
---|
| 3547 | * @param pSession The session.
|
---|
| 3548 | *
|
---|
| 3549 | * @remarks Needs only be called when dispatching events in the
|
---|
| 3550 | * VBOXGUEST_ACQUIRE_STYLE_EVENTS mask.
|
---|
| 3551 | */
|
---|
[58053] | 3552 | static uint32_t vgdrvGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
|
---|
[45760] | 3553 | {
|
---|
[54601] | 3554 | uint32_t fAcquireModeGuestCaps;
|
---|
| 3555 | uint32_t fAcquiredGuestCaps;
|
---|
| 3556 | uint32_t fAllowedEvents;
|
---|
[46196] | 3557 |
|
---|
[54601] | 3558 | /*
|
---|
[54613] | 3559 | * Note! Reads pSession->fAcquiredGuestCaps and pDevExt->fAcquireModeGuestCaps
|
---|
[54601] | 3560 | * WITHOUT holding VBOXGUESTDEVEXT::SessionSpinlock.
|
---|
| 3561 | */
|
---|
[54613] | 3562 | fAcquireModeGuestCaps = ASMAtomicUoReadU32(&pDevExt->fAcquireModeGuestCaps);
|
---|
[54601] | 3563 | if (fAcquireModeGuestCaps == 0)
|
---|
| 3564 | return VMMDEV_EVENT_VALID_EVENT_MASK;
|
---|
[54613] | 3565 | fAcquiredGuestCaps = ASMAtomicUoReadU32(&pSession->fAcquiredGuestCaps);
|
---|
[54601] | 3566 |
|
---|
| 3567 | /*
|
---|
| 3568 | * Calculate which events to allow according to the cap config and caps
|
---|
| 3569 | * acquired by the session.
|
---|
| 3570 | */
|
---|
| 3571 | fAllowedEvents = VMMDEV_EVENT_VALID_EVENT_MASK;
|
---|
| 3572 | if ( !(fAcquiredGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS)
|
---|
| 3573 | && (fAcquireModeGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS))
|
---|
| 3574 | fAllowedEvents &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
|
---|
| 3575 |
|
---|
| 3576 | if ( !(fAcquiredGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
|
---|
| 3577 | && (fAcquireModeGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS))
|
---|
| 3578 | fAllowedEvents &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
|
---|
| 3579 |
|
---|
| 3580 | return fAllowedEvents;
|
---|
| 3581 | }
|
---|
| 3582 |
|
---|
| 3583 |
|
---|
| 3584 | /**
|
---|
[54606] | 3585 | * Init and termination worker for set guest capabilities to zero on the host.
|
---|
| 3586 | *
|
---|
| 3587 | * @returns VBox status code.
|
---|
| 3588 | * @param pDevExt The device extension.
|
---|
| 3589 | */
|
---|
[58053] | 3590 | static int vgdrvResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt)
|
---|
[54606] | 3591 | {
|
---|
| 3592 | VMMDevReqGuestCapabilities2 *pReq;
|
---|
[68654] | 3593 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
|
---|
[54606] | 3594 | if (RT_SUCCESS(rc))
|
---|
| 3595 | {
|
---|
| 3596 | pReq->u32NotMask = UINT32_MAX;
|
---|
| 3597 | pReq->u32OrMask = 0;
|
---|
[68654] | 3598 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[54606] | 3599 |
|
---|
| 3600 | if (RT_FAILURE(rc))
|
---|
| 3601 | LogRelFunc(("failed with rc=%Rrc\n", rc));
|
---|
[68654] | 3602 | VbglR0GRFree(&pReq->header);
|
---|
[54606] | 3603 | }
|
---|
[62853] | 3604 | RT_NOREF1(pDevExt);
|
---|
[54606] | 3605 | return rc;
|
---|
| 3606 | }
|
---|
| 3607 |
|
---|
| 3608 |
|
---|
| 3609 | /**
|
---|
[54601] | 3610 | * Sets the guest capabilities to the host while holding the lock.
|
---|
| 3611 | *
|
---|
| 3612 | * This will ASSUME that we're the ones in charge of the mask, so
|
---|
| 3613 | * we'll simply clear all bits we don't set.
|
---|
| 3614 | *
|
---|
| 3615 | * @returns VBox status code.
|
---|
[58089] | 3616 | * @param pDevExt The device extension.
|
---|
| 3617 | * @param pReq The request.
|
---|
[54601] | 3618 | */
|
---|
[58053] | 3619 | static int vgdrvUpdateCapabilitiesOnHostWithReqAndLock(PVBOXGUESTDEVEXT pDevExt, VMMDevReqGuestCapabilities2 *pReq)
|
---|
[54601] | 3620 | {
|
---|
| 3621 | int rc;
|
---|
| 3622 |
|
---|
[54613] | 3623 | pReq->u32OrMask = pDevExt->fAcquiredGuestCaps | pDevExt->SetGuestCapsTracker.fMask;
|
---|
[54601] | 3624 | if (pReq->u32OrMask == pDevExt->fGuestCapsHost)
|
---|
| 3625 | rc = VINF_SUCCESS;
|
---|
| 3626 | else
|
---|
[46196] | 3627 | {
|
---|
[54601] | 3628 | pDevExt->fGuestCapsHost = pReq->u32OrMask;
|
---|
| 3629 | pReq->u32NotMask = ~pReq->u32OrMask;
|
---|
[68654] | 3630 | rc = VbglR0GRPerform(&pReq->header);
|
---|
[54601] | 3631 | if (RT_FAILURE(rc))
|
---|
| 3632 | pDevExt->fGuestCapsHost = UINT32_MAX;
|
---|
| 3633 | }
|
---|
| 3634 |
|
---|
| 3635 | return rc;
|
---|
| 3636 | }
|
---|
| 3637 |
|
---|
| 3638 |
|
---|
| 3639 | /**
|
---|
[54606] | 3640 | * Switch a set of capabilities into "acquire" mode and (maybe) acquire them for
|
---|
| 3641 | * the given session.
|
---|
[54601] | 3642 | *
|
---|
| 3643 | * This is called in response to VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE as well as
|
---|
| 3644 | * to do session cleanup.
|
---|
| 3645 | *
|
---|
| 3646 | * @returns VBox status code.
|
---|
| 3647 | * @param pDevExt The device extension.
|
---|
| 3648 | * @param pSession The session.
|
---|
| 3649 | * @param fOrMask The capabilities to add .
|
---|
| 3650 | * @param fNotMask The capabilities to remove. Ignored in
|
---|
| 3651 | * VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE.
|
---|
[68638] | 3652 | * @param fFlags Confusing operation modifier.
|
---|
[54601] | 3653 | * VBOXGUESTCAPSACQUIRE_FLAGS_NONE means to both
|
---|
| 3654 | * configure and acquire/release the capabilities.
|
---|
| 3655 | * VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
|
---|
| 3656 | * means only configure capabilities in the
|
---|
| 3657 | * @a fOrMask capabilities for "acquire" mode.
|
---|
| 3658 | * @param fSessionTermination Set if we're called by the session cleanup code.
|
---|
| 3659 | * This tweaks the error handling so we perform
|
---|
| 3660 | * proper session cleanup even if the host
|
---|
| 3661 | * misbehaves.
|
---|
| 3662 | *
|
---|
| 3663 | * @remarks Takes both the session and event spinlocks.
|
---|
| 3664 | */
|
---|
[58053] | 3665 | static int vgdrvAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
[68550] | 3666 | uint32_t fOrMask, uint32_t fNotMask, uint32_t fFlags,
|
---|
[58053] | 3667 | bool fSessionTermination)
|
---|
[54601] | 3668 | {
|
---|
| 3669 | uint32_t fCurrentOwnedCaps;
|
---|
| 3670 | uint32_t fSessionRemovedCaps;
|
---|
| 3671 | uint32_t fSessionAddedCaps;
|
---|
| 3672 | uint32_t fOtherConflictingCaps;
|
---|
| 3673 | VMMDevReqGuestCapabilities2 *pReq = NULL;
|
---|
| 3674 | int rc;
|
---|
| 3675 |
|
---|
| 3676 |
|
---|
| 3677 | /*
|
---|
| 3678 | * Validate and adjust input.
|
---|
| 3679 | */
|
---|
| 3680 | if (fOrMask & ~( VMMDEV_GUEST_SUPPORTS_SEAMLESS
|
---|
| 3681 | | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING
|
---|
| 3682 | | VMMDEV_GUEST_SUPPORTS_GRAPHICS ) )
|
---|
| 3683 | {
|
---|
[68550] | 3684 | LogRel(("vgdrvAcquireSessionCapabilities: invalid fOrMask=%#x (pSession=%p fNotMask=%#x fFlags=%#x)\n",
|
---|
| 3685 | fOrMask, pSession, fNotMask, fFlags));
|
---|
[46196] | 3686 | return VERR_INVALID_PARAMETER;
|
---|
| 3687 | }
|
---|
| 3688 |
|
---|
[68550] | 3689 | if ((fFlags & ~VBGL_IOC_AGC_FLAGS_VALID_MASK) != 0)
|
---|
[46196] | 3690 | {
|
---|
[68550] | 3691 | LogRel(("vgdrvAcquireSessionCapabilities: invalid fFlags=%#x (pSession=%p fOrMask=%#x fNotMask=%#x)\n",
|
---|
| 3692 | fFlags, pSession, fOrMask, fNotMask));
|
---|
[46196] | 3693 | return VERR_INVALID_PARAMETER;
|
---|
| 3694 | }
|
---|
[54606] | 3695 | Assert(!fOrMask || !fSessionTermination);
|
---|
[49946] | 3696 |
|
---|
[54601] | 3697 | /* The fNotMask no need to have all values valid, invalid ones will simply be ignored. */
|
---|
| 3698 | fNotMask &= ~fOrMask;
|
---|
| 3699 |
|
---|
| 3700 | /*
|
---|
| 3701 | * Preallocate a update request if we're about to do more than just configure
|
---|
| 3702 | * the capability mode.
|
---|
| 3703 | */
|
---|
[68550] | 3704 | if (!(fFlags & VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE))
|
---|
[45778] | 3705 | {
|
---|
[68654] | 3706 | rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
|
---|
[54606] | 3707 | if (RT_SUCCESS(rc))
|
---|
[70873] | 3708 | {
|
---|
| 3709 | if (!fSessionTermination)
|
---|
| 3710 | pReq->header.fRequestor = pSession->fRequestor;
|
---|
| 3711 | }
|
---|
[54606] | 3712 | else if (!fSessionTermination)
|
---|
[54601] | 3713 | {
|
---|
[68654] | 3714 | LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x fFlags=%#x: VbglR0GRAlloc failure: %Rrc\n",
|
---|
[68550] | 3715 | pSession, fOrMask, fNotMask, fFlags, rc));
|
---|
[54601] | 3716 | return rc;
|
---|
| 3717 | }
|
---|
[54606] | 3718 | else
|
---|
| 3719 | pReq = NULL; /* Ignore failure, we must do session cleanup. */
|
---|
[54601] | 3720 | }
|
---|
| 3721 |
|
---|
| 3722 | /*
|
---|
| 3723 | * Try switch the capabilities in the OR mask into "acquire" mode.
|
---|
| 3724 | *
|
---|
| 3725 | * Note! We currently ignore anyone which may already have "set" the capabilities
|
---|
[54606] | 3726 | * in fOrMask. Perhaps not the best way to handle it, but it's simple...
|
---|
[54601] | 3727 | */
|
---|
| 3728 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
| 3729 |
|
---|
[54613] | 3730 | if (!(pDevExt->fSetModeGuestCaps & fOrMask))
|
---|
| 3731 | pDevExt->fAcquireModeGuestCaps |= fOrMask;
|
---|
[54601] | 3732 | else
|
---|
| 3733 | {
|
---|
| 3734 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
| 3735 |
|
---|
| 3736 | if (pReq)
|
---|
[68654] | 3737 | VbglR0GRFree(&pReq->header);
|
---|
[54601] | 3738 | AssertMsgFailed(("Trying to change caps mode: %#x\n", fOrMask));
|
---|
[68550] | 3739 | LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x fFlags=%#x: calling caps acquire for set caps\n",
|
---|
| 3740 | pSession, fOrMask, fNotMask, fFlags));
|
---|
[45778] | 3741 | return VERR_INVALID_STATE;
|
---|
| 3742 | }
|
---|
[45779] | 3743 |
|
---|
[54601] | 3744 | /*
|
---|
| 3745 | * If we only wanted to switch the capabilities into "acquire" mode, we're done now.
|
---|
| 3746 | */
|
---|
[68550] | 3747 | if (fFlags & VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE)
|
---|
[46196] | 3748 | {
|
---|
[54601] | 3749 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
| 3750 |
|
---|
| 3751 | Assert(!pReq);
|
---|
[68550] | 3752 | Log(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x fFlags=%#x: configured acquire caps: 0x%x\n",
|
---|
| 3753 | pSession, fOrMask, fNotMask, fFlags));
|
---|
[46196] | 3754 | return VINF_SUCCESS;
|
---|
| 3755 | }
|
---|
[54606] | 3756 | Assert(pReq || fSessionTermination);
|
---|
[45760] | 3757 |
|
---|
[54601] | 3758 | /*
|
---|
| 3759 | * Caller wants to acquire/release the capabilities too.
|
---|
| 3760 | *
|
---|
| 3761 | * Note! The mode change of the capabilities above won't be reverted on
|
---|
| 3762 | * failure, this is intentional.
|
---|
| 3763 | */
|
---|
[54613] | 3764 | fCurrentOwnedCaps = pSession->fAcquiredGuestCaps;
|
---|
[54601] | 3765 | fSessionRemovedCaps = fCurrentOwnedCaps & fNotMask;
|
---|
| 3766 | fSessionAddedCaps = fOrMask & ~fCurrentOwnedCaps;
|
---|
[54613] | 3767 | fOtherConflictingCaps = pDevExt->fAcquiredGuestCaps & ~fCurrentOwnedCaps;
|
---|
[54601] | 3768 | fOtherConflictingCaps &= fSessionAddedCaps;
|
---|
[45760] | 3769 |
|
---|
| 3770 | if (!fOtherConflictingCaps)
|
---|
| 3771 | {
|
---|
[54601] | 3772 | if (fSessionAddedCaps)
|
---|
[45760] | 3773 | {
|
---|
[54613] | 3774 | pSession->fAcquiredGuestCaps |= fSessionAddedCaps;
|
---|
| 3775 | pDevExt->fAcquiredGuestCaps |= fSessionAddedCaps;
|
---|
[45760] | 3776 | }
|
---|
| 3777 |
|
---|
[54601] | 3778 | if (fSessionRemovedCaps)
|
---|
[45760] | 3779 | {
|
---|
[54613] | 3780 | pSession->fAcquiredGuestCaps &= ~fSessionRemovedCaps;
|
---|
| 3781 | pDevExt->fAcquiredGuestCaps &= ~fSessionRemovedCaps;
|
---|
[45760] | 3782 | }
|
---|
| 3783 |
|
---|
[54601] | 3784 | /*
|
---|
| 3785 | * If something changes (which is very likely), tell the host.
|
---|
| 3786 | */
|
---|
[54606] | 3787 | if (fSessionAddedCaps || fSessionRemovedCaps || pDevExt->fGuestCapsHost == UINT32_MAX)
|
---|
[54601] | 3788 | {
|
---|
[54606] | 3789 | Assert(pReq || fSessionTermination);
|
---|
| 3790 | if (pReq)
|
---|
[54601] | 3791 | {
|
---|
[58053] | 3792 | rc = vgdrvUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
|
---|
[54606] | 3793 | if (RT_FAILURE(rc) && !fSessionTermination)
|
---|
[54601] | 3794 | {
|
---|
[54606] | 3795 | /* Failed, roll back. */
|
---|
| 3796 | if (fSessionAddedCaps)
|
---|
| 3797 | {
|
---|
[54613] | 3798 | pSession->fAcquiredGuestCaps &= ~fSessionAddedCaps;
|
---|
| 3799 | pDevExt->fAcquiredGuestCaps &= ~fSessionAddedCaps;
|
---|
[54606] | 3800 | }
|
---|
| 3801 | if (fSessionRemovedCaps)
|
---|
| 3802 | {
|
---|
[54613] | 3803 | pSession->fAcquiredGuestCaps |= fSessionRemovedCaps;
|
---|
| 3804 | pDevExt->fAcquiredGuestCaps |= fSessionRemovedCaps;
|
---|
[54606] | 3805 | }
|
---|
| 3806 |
|
---|
| 3807 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[58053] | 3808 | LogRel(("vgdrvAcquireSessionCapabilities: vgdrvUpdateCapabilitiesOnHostWithReqAndLock failed: rc=%Rrc\n", rc));
|
---|
[68654] | 3809 | VbglR0GRFree(&pReq->header);
|
---|
[54606] | 3810 | return rc;
|
---|
[54601] | 3811 | }
|
---|
| 3812 | }
|
---|
| 3813 | }
|
---|
| 3814 | }
|
---|
| 3815 | else
|
---|
[45760] | 3816 | {
|
---|
[54601] | 3817 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
| 3818 |
|
---|
[58053] | 3819 | Log(("vgdrvAcquireSessionCapabilities: Caps %#x were busy\n", fOtherConflictingCaps));
|
---|
[68654] | 3820 | VbglR0GRFree(&pReq->header);
|
---|
[45760] | 3821 | return VERR_RESOURCE_BUSY;
|
---|
| 3822 | }
|
---|
| 3823 |
|
---|
[54601] | 3824 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[54606] | 3825 | if (pReq)
|
---|
[68654] | 3826 | VbglR0GRFree(&pReq->header);
|
---|
[45760] | 3827 |
|
---|
[54601] | 3828 | /*
|
---|
| 3829 | * If we added a capability, check if that means some other thread in our
|
---|
| 3830 | * session should be unblocked because there are events pending.
|
---|
| 3831 | *
|
---|
| 3832 | * HACK ALERT! When the seamless support capability is added we generate a
|
---|
| 3833 | * seamless change event so that the ring-3 client can sync with
|
---|
| 3834 | * the seamless state. Although this introduces a spurious
|
---|
| 3835 | * wakeups of the ring-3 client, it solves the problem of client
|
---|
| 3836 | * state inconsistency in multiuser environment (on Windows).
|
---|
| 3837 | */
|
---|
| 3838 | if (fSessionAddedCaps)
|
---|
[45760] | 3839 | {
|
---|
[54601] | 3840 | uint32_t fGenFakeEvents = 0;
|
---|
| 3841 | if (fSessionAddedCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
|
---|
| 3842 | fGenFakeEvents |= VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
|
---|
[46428] | 3843 |
|
---|
[54601] | 3844 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
| 3845 | if (fGenFakeEvents || pDevExt->f32PendingEvents)
|
---|
[58053] | 3846 | vgdrvDispatchEventsLocked(pDevExt, fGenFakeEvents);
|
---|
[54601] | 3847 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[45760] | 3848 |
|
---|
[54601] | 3849 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
[58053] | 3850 | VGDrvCommonWaitDoWakeUps(pDevExt);
|
---|
[54601] | 3851 | #endif
|
---|
[45778] | 3852 | }
|
---|
| 3853 |
|
---|
[45760] | 3854 | return VINF_SUCCESS;
|
---|
| 3855 | }
|
---|
| 3856 |
|
---|
[54237] | 3857 |
|
---|
[54601] | 3858 | /**
|
---|
[68550] | 3859 | * Handle VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES.
|
---|
[54601] | 3860 | *
|
---|
| 3861 | * @returns VBox status code.
|
---|
| 3862 | *
|
---|
| 3863 | * @param pDevExt The device extension.
|
---|
| 3864 | * @param pSession The session.
|
---|
| 3865 | * @param pAcquire The request.
|
---|
| 3866 | */
|
---|
[68550] | 3867 | static int vgdrvIoCtl_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCACQUIREGUESTCAPS pAcquire)
|
---|
[45760] | 3868 | {
|
---|
[54601] | 3869 | int rc;
|
---|
[68550] | 3870 | LogFlow(("VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES: or=%#x not=%#x flags=%#x\n",
|
---|
| 3871 | pAcquire->u.In.fOrMask, pAcquire->u.In.fNotMask, pAcquire->u.In.fFlags));
|
---|
[54601] | 3872 |
|
---|
[68550] | 3873 | rc = vgdrvAcquireSessionCapabilities(pDevExt, pSession, pAcquire->u.In.fOrMask, pAcquire->u.In.fNotMask,
|
---|
| 3874 | pAcquire->u.In.fFlags, false /*fSessionTermination*/);
|
---|
[49946] | 3875 | if (RT_FAILURE(rc))
|
---|
[68550] | 3876 | LogRel(("VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES failed rc=%Rrc\n", rc));
|
---|
| 3877 | return rc;
|
---|
[45760] | 3878 | }
|
---|
| 3879 |
|
---|
| 3880 |
|
---|
[54601] | 3881 | /**
|
---|
| 3882 | * Sets the guest capabilities for a session.
|
---|
| 3883 | *
|
---|
| 3884 | * @returns VBox status code.
|
---|
| 3885 | * @param pDevExt The device extension.
|
---|
| 3886 | * @param pSession The session.
|
---|
| 3887 | * @param fOrMask The capabilities to add.
|
---|
| 3888 | * @param fNotMask The capabilities to remove.
|
---|
[68550] | 3889 | * @param pfSessionCaps Where to return the guest capabilities reported
|
---|
| 3890 | * for this session. Optional.
|
---|
| 3891 | * @param pfGlobalCaps Where to return the guest capabilities reported
|
---|
| 3892 | * for all the sessions. Optional.
|
---|
| 3893 | *
|
---|
[54606] | 3894 | * @param fSessionTermination Set if we're called by the session cleanup code.
|
---|
| 3895 | * This tweaks the error handling so we perform
|
---|
| 3896 | * proper session cleanup even if the host
|
---|
| 3897 | * misbehaves.
|
---|
[54601] | 3898 | *
|
---|
| 3899 | * @remarks Takes the session spinlock.
|
---|
| 3900 | */
|
---|
[58053] | 3901 | static int vgdrvSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
|
---|
[68550] | 3902 | uint32_t fOrMask, uint32_t fNotMask, uint32_t *pfSessionCaps, uint32_t *pfGlobalCaps,
|
---|
| 3903 | bool fSessionTermination)
|
---|
[54601] | 3904 | {
|
---|
[54606] | 3905 | /*
|
---|
| 3906 | * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
|
---|
| 3907 | */
|
---|
| 3908 | VMMDevReqGuestCapabilities2 *pReq;
|
---|
[68654] | 3909 | int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
|
---|
[54606] | 3910 | if (RT_SUCCESS(rc))
|
---|
[70873] | 3911 | {
|
---|
| 3912 | if (!fSessionTermination)
|
---|
| 3913 | pReq->header.fRequestor = pSession->fRequestor;
|
---|
| 3914 | }
|
---|
[54606] | 3915 | else if (!fSessionTermination)
|
---|
| 3916 | {
|
---|
[68550] | 3917 | if (pfSessionCaps)
|
---|
| 3918 | *pfSessionCaps = UINT32_MAX;
|
---|
| 3919 | if (pfGlobalCaps)
|
---|
| 3920 | *pfGlobalCaps = UINT32_MAX;
|
---|
[68654] | 3921 | LogRel(("vgdrvSetSessionCapabilities: VbglR0GRAlloc failure: %Rrc\n", rc));
|
---|
[54606] | 3922 | return rc;
|
---|
| 3923 | }
|
---|
| 3924 | else
|
---|
| 3925 | pReq = NULL; /* Ignore failure, we must do session cleanup. */
|
---|
| 3926 |
|
---|
| 3927 |
|
---|
[54601] | 3928 | RTSpinlockAcquire(pDevExt->SessionSpinlock);
|
---|
| 3929 |
|
---|
| 3930 | #ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
|
---|
| 3931 | /*
|
---|
| 3932 | * Capabilities in "acquire" mode cannot be set via this API.
|
---|
| 3933 | * (Acquire mode is only used on windows at the time of writing.)
|
---|
| 3934 | */
|
---|
[54613] | 3935 | if (!(fOrMask & pDevExt->fAcquireModeGuestCaps))
|
---|
[54601] | 3936 | #endif
|
---|
| 3937 | {
|
---|
| 3938 | /*
|
---|
| 3939 | * Apply the changes to the session mask.
|
---|
| 3940 | */
|
---|
| 3941 | uint32_t fChanged;
|
---|
| 3942 | uint32_t fPrevious = pSession->fCapabilities;
|
---|
| 3943 | pSession->fCapabilities |= fOrMask;
|
---|
| 3944 | pSession->fCapabilities &= ~fNotMask;
|
---|
| 3945 |
|
---|
| 3946 | /*
|
---|
| 3947 | * If anything actually changed, update the global usage counters.
|
---|
| 3948 | */
|
---|
| 3949 | fChanged = fPrevious ^ pSession->fCapabilities;
|
---|
| 3950 | if (fChanged)
|
---|
| 3951 | {
|
---|
[58053] | 3952 | bool fGlobalChange = vgdrvBitUsageTrackerChange(&pDevExt->SetGuestCapsTracker, fChanged, fPrevious,
|
---|
| 3953 | pDevExt->cSessions, "SetGuestCapsTracker");
|
---|
[54601] | 3954 |
|
---|
| 3955 | /*
|
---|
[54606] | 3956 | * If there are global changes, update the capabilities on the host.
|
---|
[54601] | 3957 | */
|
---|
[54606] | 3958 | if (fGlobalChange || pDevExt->fGuestCapsHost == UINT32_MAX)
|
---|
[54601] | 3959 | {
|
---|
[54606] | 3960 | Assert(pReq || fSessionTermination);
|
---|
| 3961 | if (pReq)
|
---|
| 3962 | {
|
---|
[58053] | 3963 | rc = vgdrvUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
|
---|
[54601] | 3964 |
|
---|
[54606] | 3965 | /* On failure, roll back (unless it's session termination time). */
|
---|
| 3966 | if (RT_FAILURE(rc) && !fSessionTermination)
|
---|
| 3967 | {
|
---|
[58053] | 3968 | vgdrvBitUsageTrackerChange(&pDevExt->SetGuestCapsTracker, fChanged, pSession->fCapabilities,
|
---|
| 3969 | pDevExt->cSessions, "SetGuestCapsTracker");
|
---|
[54606] | 3970 | pSession->fCapabilities = fPrevious;
|
---|
| 3971 | }
|
---|
| 3972 | }
|
---|
[54601] | 3973 | }
|
---|
| 3974 | }
|
---|
| 3975 | }
|
---|
| 3976 | #ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
|
---|
| 3977 | else
|
---|
| 3978 | rc = VERR_RESOURCE_BUSY;
|
---|
| 3979 | #endif
|
---|
| 3980 |
|
---|
[68550] | 3981 | if (pfSessionCaps)
|
---|
| 3982 | *pfSessionCaps = pSession->fCapabilities;
|
---|
| 3983 | if (pfGlobalCaps)
|
---|
| 3984 | *pfGlobalCaps = pDevExt->fAcquiredGuestCaps | pDevExt->SetGuestCapsTracker.fMask;
|
---|
| 3985 |
|
---|
[54601] | 3986 | RTSpinlockRelease(pDevExt->SessionSpinlock);
|
---|
[54606] | 3987 | if (pReq)
|
---|
[68654] | 3988 | VbglR0GRFree(&pReq->header);
|
---|
[54601] | 3989 | return rc;
|
---|
| 3990 | }
|
---|
| 3991 |
|
---|
| 3992 |
|
---|
| 3993 | /**
|
---|
[68550] | 3994 | * Handle VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES.
|
---|
[54601] | 3995 | *
|
---|
| 3996 | * @returns VBox status code.
|
---|
| 3997 | *
|
---|
| 3998 | * @param pDevExt The device extension.
|
---|
| 3999 | * @param pSession The session.
|
---|
| 4000 | * @param pInfo The request.
|
---|
| 4001 | */
|
---|
[68550] | 4002 | static int vgdrvIoCtl_SetCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLIOCSETGUESTCAPS pInfo)
|
---|
[54593] | 4003 | {
|
---|
| 4004 | int rc;
|
---|
[68550] | 4005 | LogFlow(("VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES: or=%#x not=%#x\n", pInfo->u.In.fOrMask, pInfo->u.In.fNotMask));
|
---|
[54593] | 4006 |
|
---|
[68550] | 4007 | if (!((pInfo->u.In.fOrMask | pInfo->u.In.fNotMask) & ~VMMDEV_GUEST_CAPABILITIES_MASK))
|
---|
| 4008 | rc = vgdrvSetSessionCapabilities(pDevExt, pSession, pInfo->u.In.fOrMask, pInfo->u.In.fNotMask,
|
---|
| 4009 | &pInfo->u.Out.fSessionCaps, &pInfo->u.Out.fGlobalCaps, false /*fSessionTermination*/);
|
---|
[54601] | 4010 | else
|
---|
| 4011 | rc = VERR_INVALID_PARAMETER;
|
---|
| 4012 |
|
---|
[54593] | 4013 | return rc;
|
---|
| 4014 | }
|
---|
| 4015 |
|
---|
| 4016 | /** @} */
|
---|
| 4017 |
|
---|
| 4018 |
|
---|
[6436] | 4019 | /**
|
---|
[33540] | 4020 | * Common IOCtl for user to kernel and kernel to kernel communication.
|
---|
[6032] | 4021 | *
|
---|
| 4022 | * This function only does the basic validation and then invokes
|
---|
[3657] | 4023 | * worker functions that takes care of each specific function.
|
---|
[6032] | 4024 | *
|
---|
[3657] | 4025 | * @returns VBox status code.
|
---|
[6032] | 4026 | *
|
---|
[3657] | 4027 | * @param iFunction The requested function.
|
---|
| 4028 | * @param pDevExt The device extension.
|
---|
| 4029 | * @param pSession The client session.
|
---|
[68550] | 4030 | * @param pReqHdr Pointer to the request. This always starts with
|
---|
| 4031 | * a request common header.
|
---|
| 4032 | * @param cbReq The max size of the request buffer.
|
---|
[3657] | 4033 | */
|
---|
[68550] | 4034 | int VGDrvCommonIoCtl(uintptr_t iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, PVBGLREQHDR pReqHdr, size_t cbReq)
|
---|
[3657] | 4035 | {
|
---|
[68550] | 4036 | uintptr_t const iFunctionStripped = VBGL_IOCTL_CODE_STRIPPED(iFunction);
|
---|
[31720] | 4037 | int rc;
|
---|
[3657] | 4038 |
|
---|
[68550] | 4039 | LogFlow(("VGDrvCommonIoCtl: iFunction=%#x pDevExt=%p pSession=%p pReqHdr=%p cbReq=%zu\n",
|
---|
| 4040 | iFunction, pDevExt, pSession, pReqHdr, cbReq));
|
---|
[21376] | 4041 |
|
---|
| 4042 | /*
|
---|
[3657] | 4043 | * Define some helper macros to simplify validation.
|
---|
| 4044 | */
|
---|
[68550] | 4045 | #define REQ_CHECK_SIZES_EX(Name, cbInExpect, cbOutExpect) \
|
---|
[3657] | 4046 | do { \
|
---|
[68550] | 4047 | if (RT_LIKELY( pReqHdr->cbIn == (cbInExpect) \
|
---|
| 4048 | && ( pReqHdr->cbOut == (cbOutExpect) \
|
---|
| 4049 | || ((cbInExpect) == (cbOutExpect) && pReqHdr->cbOut == 0) ) )) \
|
---|
| 4050 | { /* likely */ } \
|
---|
| 4051 | else \
|
---|
[3657] | 4052 | { \
|
---|
[68550] | 4053 | Log(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld. cbOut=%ld expected %ld.\n", \
|
---|
| 4054 | (long)pReqHdr->cbIn, (long)(cbInExpect), (long)pReqHdr->cbOut, (long)(cbOutExpect))); \
|
---|
| 4055 | return pReqHdr->rc = VERR_INVALID_PARAMETER; \
|
---|
[3657] | 4056 | } \
|
---|
| 4057 | } while (0)
|
---|
[68550] | 4058 |
|
---|
| 4059 | #define REQ_CHECK_SIZES(Name) REQ_CHECK_SIZES_EX(Name, Name ## _SIZE_IN, Name ## _SIZE_OUT)
|
---|
| 4060 |
|
---|
| 4061 | #define REQ_CHECK_SIZE_IN(Name, cbInExpect) \
|
---|
[3657] | 4062 | do { \
|
---|
[68550] | 4063 | if (RT_LIKELY(pReqHdr->cbIn == (cbInExpect))) \
|
---|
| 4064 | { /* likely */ } \
|
---|
| 4065 | else \
|
---|
[3657] | 4066 | { \
|
---|
[68550] | 4067 | Log(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld.\n", \
|
---|
| 4068 | (long)pReqHdr->cbIn, (long)(cbInExpect))); \
|
---|
| 4069 | return pReqHdr->rc = VERR_INVALID_PARAMETER; \
|
---|
[3657] | 4070 | } \
|
---|
[68550] | 4071 | } while (0)
|
---|
| 4072 |
|
---|
| 4073 | #define REQ_CHECK_SIZE_OUT(Name, cbOutExpect) \
|
---|
| 4074 | do { \
|
---|
| 4075 | if (RT_LIKELY( pReqHdr->cbOut == (cbOutExpect) \
|
---|
| 4076 | || (pReqHdr->cbOut == 0 && pReqHdr->cbIn == (cbOutExpect)))) \
|
---|
| 4077 | { /* likely */ } \
|
---|
| 4078 | else \
|
---|
[3657] | 4079 | { \
|
---|
[68550] | 4080 | Log(( #Name ": Invalid input/output sizes. cbOut=%ld (%ld) expected %ld.\n", \
|
---|
| 4081 | (long)pReqHdr->cbOut, (long)pReqHdr->cbIn, (long)(cbOutExpect))); \
|
---|
| 4082 | return pReqHdr->rc = VERR_INVALID_PARAMETER; \
|
---|
[3657] | 4083 | } \
|
---|
| 4084 | } while (0)
|
---|
[68550] | 4085 |
|
---|
| 4086 | #define REQ_CHECK_EXPR(Name, expr) \
|
---|
[38592] | 4087 | do { \
|
---|
[68550] | 4088 | if (RT_LIKELY(!!(expr))) \
|
---|
| 4089 | { /* likely */ } \
|
---|
| 4090 | else \
|
---|
[38592] | 4091 | { \
|
---|
[68550] | 4092 | Log(( #Name ": %s\n", #expr)); \
|
---|
| 4093 | return pReqHdr->rc = VERR_INVALID_PARAMETER; \
|
---|
[38592] | 4094 | } \
|
---|
[68550] | 4095 | } while (0)
|
---|
| 4096 |
|
---|
| 4097 | #define REQ_CHECK_EXPR_FMT(expr, fmt) \
|
---|
| 4098 | do { \
|
---|
| 4099 | if (RT_LIKELY(!!(expr))) \
|
---|
| 4100 | { /* likely */ } \
|
---|
| 4101 | else \
|
---|
[38592] | 4102 | { \
|
---|
[68550] | 4103 | Log( fmt ); \
|
---|
| 4104 | return pReqHdr->rc = VERR_INVALID_PARAMETER; \
|
---|
[38592] | 4105 | } \
|
---|
| 4106 | } while (0)
|
---|
[3657] | 4107 |
|
---|
[68550] | 4108 | #define REQ_CHECK_RING0(mnemonic) \
|
---|
| 4109 | do { \
|
---|
| 4110 | if (pSession->R0Process != NIL_RTR0PROCESS) \
|
---|
| 4111 | { \
|
---|
| 4112 | LogFunc((mnemonic ": Ring-0 only, caller is %RTproc/%p\n", \
|
---|
| 4113 | pSession->Process, (uintptr_t)pSession->R0Process)); \
|
---|
| 4114 | return pReqHdr->rc = VERR_PERMISSION_DENIED; \
|
---|
| 4115 | } \
|
---|
| 4116 | } while (0)
|
---|
[3657] | 4117 |
|
---|
[68550] | 4118 |
|
---|
[6032] | 4119 | /*
|
---|
[68550] | 4120 | * Validate the request.
|
---|
[3657] | 4121 | */
|
---|
[68550] | 4122 | if (RT_LIKELY(cbReq >= sizeof(*pReqHdr)))
|
---|
| 4123 | { /* likely */ }
|
---|
| 4124 | else
|
---|
[3657] | 4125 | {
|
---|
[68550] | 4126 | Log(("VGDrvCommonIoCtl: Bad ioctl request size; cbReq=%#lx\n", (long)cbReq));
|
---|
| 4127 | return VERR_INVALID_PARAMETER;
|
---|
[3657] | 4128 | }
|
---|
[68550] | 4129 |
|
---|
| 4130 | if (pReqHdr->cbOut == 0)
|
---|
| 4131 | pReqHdr->cbOut = pReqHdr->cbIn;
|
---|
| 4132 |
|
---|
| 4133 | if (RT_LIKELY( pReqHdr->uVersion == VBGLREQHDR_VERSION
|
---|
| 4134 | && pReqHdr->cbIn >= sizeof(*pReqHdr)
|
---|
| 4135 | && pReqHdr->cbIn <= cbReq
|
---|
| 4136 | && pReqHdr->cbOut >= sizeof(*pReqHdr)
|
---|
| 4137 | && pReqHdr->cbOut <= cbReq))
|
---|
| 4138 | { /* likely */ }
|
---|
| 4139 | else
|
---|
[3657] | 4140 | {
|
---|
[68550] | 4141 | Log(("VGDrvCommonIoCtl: Bad ioctl request header; cbIn=%#lx cbOut=%#lx version=%#lx\n",
|
---|
| 4142 | (long)pReqHdr->cbIn, (long)pReqHdr->cbOut, (long)pReqHdr->uVersion));
|
---|
| 4143 | return VERR_INVALID_PARAMETER;
|
---|
[3657] | 4144 | }
|
---|
[68550] | 4145 |
|
---|
| 4146 | if (RT_LIKELY(RT_VALID_PTR(pSession)))
|
---|
| 4147 | { /* likely */ }
|
---|
| 4148 | else
|
---|
[14221] | 4149 | {
|
---|
[68550] | 4150 | Log(("VGDrvCommonIoCtl: Invalid pSession value %p (ioctl=%#x)\n", pSession, iFunction));
|
---|
| 4151 | return VERR_INVALID_PARAMETER;
|
---|
[14221] | 4152 | }
|
---|
[68550] | 4153 |
|
---|
| 4154 |
|
---|
| 4155 | /*
|
---|
| 4156 | * Deal with variably sized requests first.
|
---|
| 4157 | */
|
---|
| 4158 | rc = VINF_SUCCESS;
|
---|
| 4159 | if ( iFunctionStripped == VBGL_IOCTL_CODE_STRIPPED(VBGL_IOCTL_VMMDEV_REQUEST(0))
|
---|
| 4160 | || iFunctionStripped == VBGL_IOCTL_CODE_STRIPPED(VBGL_IOCTL_VMMDEV_REQUEST_BIG) )
|
---|
[40483] | 4161 | {
|
---|
[68550] | 4162 | REQ_CHECK_EXPR(VBGL_IOCTL_VMMDEV_REQUEST, pReqHdr->uType != VBGLREQHDR_TYPE_DEFAULT);
|
---|
| 4163 | REQ_CHECK_EXPR_FMT(pReqHdr->cbIn == pReqHdr->cbOut,
|
---|
| 4164 | ("VBGL_IOCTL_VMMDEV_REQUEST: cbIn=%ld != cbOut=%ld\n", (long)pReqHdr->cbIn, (long)pReqHdr->cbOut));
|
---|
| 4165 | pReqHdr->rc = vgdrvIoCtl_VMMDevRequest(pDevExt, pSession, (VMMDevRequestHeader *)pReqHdr, cbReq);
|
---|
[40483] | 4166 | }
|
---|
[68550] | 4167 | else if (RT_LIKELY(pReqHdr->uType == VBGLREQHDR_TYPE_DEFAULT))
|
---|
[17196] | 4168 | {
|
---|
[68550] | 4169 | if (iFunctionStripped == VBGL_IOCTL_CODE_STRIPPED(VBGL_IOCTL_LOG(0)))
|
---|
| 4170 | {
|
---|
| 4171 | REQ_CHECK_SIZE_OUT(VBGL_IOCTL_LOG, VBGL_IOCTL_LOG_SIZE_OUT);
|
---|
| 4172 | pReqHdr->rc = vgdrvIoCtl_Log(pDevExt, &((PVBGLIOCLOG)pReqHdr)->u.In.szMsg[0], pReqHdr->cbIn - sizeof(VBGLREQHDR),
|
---|
| 4173 | pSession->fUserSession);
|
---|
| 4174 | }
|
---|
| 4175 | #ifdef VBOX_WITH_HGCM
|
---|
[75547] | 4176 | else if (iFunction == VBGL_IOCTL_IDC_HGCM_FAST_CALL) /* (is variable size, but we don't bother encoding it) */
|
---|
| 4177 | {
|
---|
| 4178 | REQ_CHECK_RING0("VBGL_IOCTL_IDC_HGCM_FAST_CALL");
|
---|
| 4179 | REQ_CHECK_EXPR(VBGL_IOCTL_IDC_HGCM_FAST_CALL, cbReq >= sizeof(VBGLIOCIDCHGCMFASTCALL) + sizeof(VMMDevHGCMCall));
|
---|
[80041] | 4180 | pReqHdr->rc = vgdrvIoCtl_HGCMFastCall(pDevExt, (VBGLIOCIDCHGCMFASTCALL volatile *)pReqHdr);
|
---|
[75547] | 4181 | }
|
---|
[68623] | 4182 | else if ( iFunctionStripped == VBGL_IOCTL_CODE_STRIPPED(VBGL_IOCTL_HGCM_CALL(0))
|
---|
| 4183 | # if ARCH_BITS == 64
|
---|
| 4184 | || iFunctionStripped == VBGL_IOCTL_CODE_STRIPPED(VBGL_IOCTL_HGCM_CALL_32(0))
|
---|
| 4185 | # endif
|
---|
| 4186 | )
|
---|
[68550] | 4187 | {
|
---|
| 4188 | REQ_CHECK_EXPR(VBGL_IOCTL_HGCM_CALL, pReqHdr->cbIn >= sizeof(VBGLIOCHGCMCALL));
|
---|
| 4189 | REQ_CHECK_EXPR(VBGL_IOCTL_HGCM_CALL, pReqHdr->cbIn == pReqHdr->cbOut);
|
---|
| 4190 | pReqHdr->rc = vgdrvIoCtl_HGCMCallWrapper(pDevExt, pSession, (PVBGLIOCHGCMCALL)pReqHdr,
|
---|
[68623] | 4191 | iFunctionStripped == VBGL_IOCTL_CODE_STRIPPED(VBGL_IOCTL_HGCM_CALL_32(0)),
|
---|
| 4192 | false /*fUserData*/, cbReq);
|
---|
[68550] | 4193 | }
|
---|
| 4194 | else if (iFunctionStripped == VBGL_IOCTL_CODE_STRIPPED(VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA(0)))
|
---|
| 4195 | {
|
---|
| 4196 | REQ_CHECK_RING0("VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA");
|
---|
| 4197 | REQ_CHECK_EXPR(VBGL_IOCTL_HGCM_CALL, pReqHdr->cbIn >= sizeof(VBGLIOCHGCMCALL));
|
---|
| 4198 | REQ_CHECK_EXPR(VBGL_IOCTL_HGCM_CALL, pReqHdr->cbIn == pReqHdr->cbOut);
|
---|
| 4199 | pReqHdr->rc = vgdrvIoCtl_HGCMCallWrapper(pDevExt, pSession, (PVBGLIOCHGCMCALL)pReqHdr,
|
---|
[68623] | 4200 | ARCH_BITS == 32, true /*fUserData*/, cbReq);
|
---|
[68550] | 4201 | }
|
---|
[11820] | 4202 | #endif /* VBOX_WITH_HGCM */
|
---|
[68550] | 4203 | else
|
---|
[3657] | 4204 | {
|
---|
[68550] | 4205 | switch (iFunction)
|
---|
| 4206 | {
|
---|
| 4207 | /*
|
---|
| 4208 | * Ring-0 only:
|
---|
| 4209 | */
|
---|
| 4210 | case VBGL_IOCTL_IDC_CONNECT:
|
---|
| 4211 | REQ_CHECK_RING0("VBGL_IOCL_IDC_CONNECT");
|
---|
| 4212 | REQ_CHECK_SIZES(VBGL_IOCTL_IDC_CONNECT);
|
---|
| 4213 | pReqHdr->rc = vgdrvIoCtl_IdcConnect(pDevExt, pSession, (PVBGLIOCIDCCONNECT)pReqHdr);
|
---|
| 4214 | break;
|
---|
[3657] | 4215 |
|
---|
[68550] | 4216 | case VBGL_IOCTL_IDC_DISCONNECT:
|
---|
| 4217 | REQ_CHECK_RING0("VBGL_IOCTL_IDC_DISCONNECT");
|
---|
| 4218 | REQ_CHECK_SIZES(VBGL_IOCTL_IDC_DISCONNECT);
|
---|
| 4219 | pReqHdr->rc = vgdrvIoCtl_IdcDisconnect(pDevExt, pSession, (PVBGLIOCIDCDISCONNECT)pReqHdr);
|
---|
| 4220 | break;
|
---|
[41640] | 4221 |
|
---|
[68550] | 4222 | case VBGL_IOCTL_GET_VMMDEV_IO_INFO:
|
---|
| 4223 | REQ_CHECK_RING0("GET_VMMDEV_IO_INFO");
|
---|
| 4224 | REQ_CHECK_SIZES(VBGL_IOCTL_GET_VMMDEV_IO_INFO);
|
---|
| 4225 | pReqHdr->rc = vgdrvIoCtl_GetVMMDevIoInfo(pDevExt, (PVBGLIOCGETVMMDEVIOINFO)pReqHdr);
|
---|
| 4226 | break;
|
---|
[3657] | 4227 |
|
---|
[68550] | 4228 | case VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK:
|
---|
| 4229 | REQ_CHECK_RING0("SET_MOUSE_NOTIFY_CALLBACK");
|
---|
| 4230 | REQ_CHECK_SIZES(VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK);
|
---|
| 4231 | pReqHdr->rc = vgdrvIoCtl_SetMouseNotifyCallback(pDevExt, (PVBGLIOCSETMOUSENOTIFYCALLBACK)pReqHdr);
|
---|
| 4232 | break;
|
---|
[21491] | 4233 |
|
---|
[68550] | 4234 | /*
|
---|
| 4235 | * Ring-3 only:
|
---|
| 4236 | */
|
---|
| 4237 | case VBGL_IOCTL_DRIVER_VERSION_INFO:
|
---|
| 4238 | REQ_CHECK_SIZES(VBGL_IOCTL_DRIVER_VERSION_INFO);
|
---|
| 4239 | pReqHdr->rc = vgdrvIoCtl_DriverVersionInfo(pDevExt, pSession, (PVBGLIOCDRIVERVERSIONINFO)pReqHdr);
|
---|
| 4240 | break;
|
---|
[3657] | 4241 |
|
---|
[68550] | 4242 | /*
|
---|
| 4243 | * Both ring-3 and ring-0:
|
---|
| 4244 | */
|
---|
| 4245 | case VBGL_IOCTL_WAIT_FOR_EVENTS:
|
---|
| 4246 | REQ_CHECK_SIZES(VBGL_IOCTL_WAIT_FOR_EVENTS);
|
---|
| 4247 | pReqHdr->rc = vgdrvIoCtl_WaitForEvents(pDevExt, pSession, (VBGLIOCWAITFOREVENTS *)pReqHdr,
|
---|
| 4248 | pSession->R0Process != NIL_RTR0PROCESS);
|
---|
| 4249 | break;
|
---|
| 4250 |
|
---|
| 4251 | case VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS:
|
---|
| 4252 | REQ_CHECK_SIZES(VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS);
|
---|
| 4253 | pReqHdr->rc = vgdrvIoCtl_CancelAllWaitEvents(pDevExt, pSession);
|
---|
| 4254 | break;
|
---|
| 4255 |
|
---|
| 4256 | case VBGL_IOCTL_CHANGE_FILTER_MASK:
|
---|
| 4257 | REQ_CHECK_SIZES(VBGL_IOCTL_CHANGE_FILTER_MASK);
|
---|
| 4258 | pReqHdr->rc = vgdrvIoCtl_ChangeFilterMask(pDevExt, pSession, (PVBGLIOCCHANGEFILTERMASK)pReqHdr);
|
---|
| 4259 | break;
|
---|
| 4260 |
|
---|
[11820] | 4261 | #ifdef VBOX_WITH_HGCM
|
---|
[68550] | 4262 | case VBGL_IOCTL_HGCM_CONNECT:
|
---|
| 4263 | REQ_CHECK_SIZES(VBGL_IOCTL_HGCM_CONNECT);
|
---|
| 4264 | pReqHdr->rc = vgdrvIoCtl_HGCMConnect(pDevExt, pSession, (PVBGLIOCHGCMCONNECT)pReqHdr);
|
---|
| 4265 | break;
|
---|
[3657] | 4266 |
|
---|
[68550] | 4267 | case VBGL_IOCTL_HGCM_DISCONNECT:
|
---|
| 4268 | REQ_CHECK_SIZES(VBGL_IOCTL_HGCM_DISCONNECT);
|
---|
| 4269 | pReqHdr->rc = vgdrvIoCtl_HGCMDisconnect(pDevExt, pSession, (PVBGLIOCHGCMDISCONNECT)pReqHdr);
|
---|
| 4270 | break;
|
---|
| 4271 | #endif
|
---|
[3657] | 4272 |
|
---|
[68550] | 4273 | case VBGL_IOCTL_CHECK_BALLOON:
|
---|
| 4274 | REQ_CHECK_SIZES(VBGL_IOCTL_CHECK_BALLOON);
|
---|
| 4275 | pReqHdr->rc = vgdrvIoCtl_CheckMemoryBalloon(pDevExt, pSession, (PVBGLIOCCHECKBALLOON)pReqHdr);
|
---|
| 4276 | break;
|
---|
[26934] | 4277 |
|
---|
[68550] | 4278 | case VBGL_IOCTL_CHANGE_BALLOON:
|
---|
| 4279 | REQ_CHECK_SIZES(VBGL_IOCTL_CHANGE_BALLOON);
|
---|
| 4280 | pReqHdr->rc = vgdrvIoCtl_ChangeMemoryBalloon(pDevExt, pSession, (PVBGLIOCCHANGEBALLOON)pReqHdr);
|
---|
| 4281 | break;
|
---|
[26999] | 4282 |
|
---|
[68550] | 4283 | case VBGL_IOCTL_WRITE_CORE_DUMP:
|
---|
| 4284 | REQ_CHECK_SIZES(VBGL_IOCTL_WRITE_CORE_DUMP);
|
---|
[70873] | 4285 | pReqHdr->rc = vgdrvIoCtl_WriteCoreDump(pDevExt, pSession, (PVBGLIOCWRITECOREDUMP)pReqHdr);
|
---|
[68550] | 4286 | break;
|
---|
[32574] | 4287 |
|
---|
[68550] | 4288 | case VBGL_IOCTL_SET_MOUSE_STATUS:
|
---|
| 4289 | REQ_CHECK_SIZES(VBGL_IOCTL_SET_MOUSE_STATUS);
|
---|
| 4290 | pReqHdr->rc = vgdrvIoCtl_SetMouseStatus(pDevExt, pSession, ((PVBGLIOCSETMOUSESTATUS)pReqHdr)->u.In.fStatus);
|
---|
| 4291 | break;
|
---|
[32266] | 4292 |
|
---|
[68550] | 4293 | case VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES:
|
---|
| 4294 | REQ_CHECK_SIZES(VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES);
|
---|
| 4295 | pReqHdr->rc = vgdrvIoCtl_GuestCapsAcquire(pDevExt, pSession, (PVBGLIOCACQUIREGUESTCAPS)pReqHdr);
|
---|
| 4296 | break;
|
---|
| 4297 |
|
---|
| 4298 | case VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES:
|
---|
| 4299 | REQ_CHECK_SIZES(VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES);
|
---|
| 4300 | pReqHdr->rc = vgdrvIoCtl_SetCapabilities(pDevExt, pSession, (PVBGLIOCSETGUESTCAPS)pReqHdr);
|
---|
| 4301 | break;
|
---|
| 4302 |
|
---|
[44992] | 4303 | #ifdef VBOX_WITH_DPC_LATENCY_CHECKER
|
---|
[68550] | 4304 | case VBGL_IOCTL_DPC_LATENCY_CHECKER:
|
---|
| 4305 | REQ_CHECK_SIZES(VBGL_IOCTL_DPC_LATENCY_CHECKER);
|
---|
| 4306 | pReqHdr->rc = VGDrvNtIOCtl_DpcLatencyChecker();
|
---|
| 4307 | break;
|
---|
[44992] | 4308 | #endif
|
---|
| 4309 |
|
---|
[68550] | 4310 | default:
|
---|
| 4311 | {
|
---|
| 4312 | LogRel(("VGDrvCommonIoCtl: Unknown request iFunction=%#x (stripped %#x) cbReq=%#x\n",
|
---|
| 4313 | iFunction, iFunctionStripped, cbReq));
|
---|
| 4314 | pReqHdr->rc = rc = VERR_NOT_SUPPORTED;
|
---|
| 4315 | break;
|
---|
| 4316 | }
|
---|
[3657] | 4317 | }
|
---|
| 4318 | }
|
---|
| 4319 | }
|
---|
[68550] | 4320 | else
|
---|
| 4321 | {
|
---|
| 4322 | Log(("VGDrvCommonIoCtl: uType=%#x, expected default (ioctl=%#x)\n", pReqHdr->uType, iFunction));
|
---|
| 4323 | return VERR_INVALID_PARAMETER;
|
---|
| 4324 | }
|
---|
[3657] | 4325 |
|
---|
[68550] | 4326 | LogFlow(("VGDrvCommonIoCtl: returns %Rrc (req: rc=%Rrc cbOut=%#x)\n", rc, pReqHdr->rc, pReqHdr->cbOut));
|
---|
[3657] | 4327 | return rc;
|
---|
| 4328 | }
|
---|
| 4329 |
|
---|
| 4330 |
|
---|
[54601] | 4331 | /**
|
---|
[58053] | 4332 | * Used by VGDrvCommonISR as well as the acquire guest capability code.
|
---|
[54601] | 4333 | *
|
---|
| 4334 | * @returns VINF_SUCCESS on success. On failure, ORed together
|
---|
| 4335 | * RTSemEventMultiSignal errors (completes processing despite errors).
|
---|
| 4336 | * @param pDevExt The VBoxGuest device extension.
|
---|
| 4337 | * @param fEvents The events to dispatch.
|
---|
| 4338 | */
|
---|
[58053] | 4339 | static int vgdrvDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents)
|
---|
[54601] | 4340 | {
|
---|
| 4341 | PVBOXGUESTWAIT pWait;
|
---|
| 4342 | PVBOXGUESTWAIT pSafe;
|
---|
| 4343 | int rc = VINF_SUCCESS;
|
---|
[3657] | 4344 |
|
---|
[54601] | 4345 | fEvents |= pDevExt->f32PendingEvents;
|
---|
| 4346 |
|
---|
| 4347 | RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
|
---|
| 4348 | {
|
---|
| 4349 | uint32_t fHandledEvents = pWait->fReqEvents & fEvents;
|
---|
| 4350 | if ( fHandledEvents != 0
|
---|
| 4351 | && !pWait->fResEvents)
|
---|
| 4352 | {
|
---|
| 4353 | /* Does this one wait on any of the events we're dispatching? We do a quick
|
---|
| 4354 | check first, then deal with VBOXGUEST_ACQUIRE_STYLE_EVENTS as applicable. */
|
---|
| 4355 | if (fHandledEvents & VBOXGUEST_ACQUIRE_STYLE_EVENTS)
|
---|
[58053] | 4356 | fHandledEvents &= vgdrvGetAllowedEventMaskForSession(pDevExt, pWait->pSession);
|
---|
[54601] | 4357 | if (fHandledEvents)
|
---|
| 4358 | {
|
---|
| 4359 | pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents;
|
---|
| 4360 | fEvents &= ~pWait->fResEvents;
|
---|
| 4361 | RTListNodeRemove(&pWait->ListNode);
|
---|
| 4362 | #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
| 4363 | RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
|
---|
| 4364 | #else
|
---|
| 4365 | RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
|
---|
| 4366 | rc |= RTSemEventMultiSignal(pWait->Event);
|
---|
| 4367 | #endif
|
---|
| 4368 | if (!fEvents)
|
---|
| 4369 | break;
|
---|
| 4370 | }
|
---|
| 4371 | }
|
---|
| 4372 | }
|
---|
| 4373 |
|
---|
| 4374 | ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents);
|
---|
| 4375 | return rc;
|
---|
| 4376 | }
|
---|
| 4377 |
|
---|
| 4378 |
|
---|
[3657] | 4379 | /**
|
---|
[64435] | 4380 | * Simply checks whether the IRQ is ours or not, does not do any interrupt
|
---|
| 4381 | * procesing.
|
---|
| 4382 | *
|
---|
| 4383 | * @returns true if it was our interrupt, false if it wasn't.
|
---|
| 4384 | * @param pDevExt The VBoxGuest device extension.
|
---|
| 4385 | */
|
---|
[64436] | 4386 | bool VGDrvCommonIsOurIRQ(PVBOXGUESTDEVEXT pDevExt)
|
---|
[64435] | 4387 | {
|
---|
[70226] | 4388 | VMMDevMemory volatile *pVMMDevMemory;
|
---|
| 4389 | bool fOurIrq;
|
---|
| 4390 |
|
---|
[64435] | 4391 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[70226] | 4392 | pVMMDevMemory = pDevExt->pVMMDevMemory;
|
---|
| 4393 | fOurIrq = pVMMDevMemory ? pVMMDevMemory->V.V1_04.fHaveEvents : false;
|
---|
[64435] | 4394 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
| 4395 |
|
---|
| 4396 | return fOurIrq;
|
---|
| 4397 | }
|
---|
| 4398 |
|
---|
| 4399 |
|
---|
| 4400 | /**
|
---|
[3657] | 4401 | * Common interrupt service routine.
|
---|
[6032] | 4402 | *
|
---|
[3657] | 4403 | * This deals with events and with waking up thread waiting for those events.
|
---|
[6032] | 4404 | *
|
---|
[3657] | 4405 | * @returns true if it was our interrupt, false if it wasn't.
|
---|
| 4406 | * @param pDevExt The VBoxGuest device extension.
|
---|
| 4407 | */
|
---|
[58053] | 4408 | bool VGDrvCommonISR(PVBOXGUESTDEVEXT pDevExt)
|
---|
[3657] | 4409 | {
|
---|
[75588] | 4410 | VMMDevEvents volatile *pReq;
|
---|
[54608] | 4411 | bool fMousePositionChanged = false;
|
---|
| 4412 | int rc = 0;
|
---|
[70226] | 4413 | VMMDevMemory volatile *pVMMDevMemory;
|
---|
[54608] | 4414 | bool fOurIrq;
|
---|
[21376] | 4415 |
|
---|
[3657] | 4416 | /*
|
---|
[33540] | 4417 | * Make sure we've initialized the device extension.
|
---|
[3657] | 4418 | */
|
---|
[75588] | 4419 | if (RT_LIKELY(pDevExt->fHostFeatures & VMMDEV_HVF_FAST_IRQ_ACK))
|
---|
| 4420 | pReq = NULL;
|
---|
| 4421 | else if (RT_LIKELY((pReq = pDevExt->pIrqAckEvents) != NULL))
|
---|
| 4422 | { /* likely */ }
|
---|
| 4423 | else
|
---|
[21376] | 4424 | return false;
|
---|
| 4425 |
|
---|
| 4426 | /*
|
---|
[50537] | 4427 | * Enter the spinlock and check if it's our IRQ or not.
|
---|
[21376] | 4428 | */
|
---|
[40806] | 4429 | RTSpinlockAcquire(pDevExt->EventSpinlock);
|
---|
[70226] | 4430 | pVMMDevMemory = pDevExt->pVMMDevMemory;
|
---|
| 4431 | fOurIrq = pVMMDevMemory ? pVMMDevMemory->V.V1_04.fHaveEvents : false;
|
---|
[3657] | 4432 | if (fOurIrq)
|
---|
| 4433 | {
|
---|
[21376] | 4434 | /*
|
---|
[75588] | 4435 | * Acknowledge events.
|
---|
[68654] | 4436 | * We don't use VbglR0GRPerform here as it may take another spinlocks.
|
---|
[21376] | 4437 | */
|
---|
[75588] | 4438 | uint32_t fEvents;
|
---|
| 4439 | if (!pReq)
|
---|
[3657] | 4440 | {
|
---|
[100267] | 4441 | if (pDevExt->pMmioReqFast)
|
---|
| 4442 | fEvents = *pDevExt->pMmioReqFast;
|
---|
| 4443 | else
|
---|
| 4444 | {
|
---|
| 4445 | #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
|
---|
| 4446 | fEvents = ASMInU32(pDevExt->IOPortBase + VMMDEV_PORT_OFF_REQUEST_FAST);
|
---|
| 4447 | #elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
|
---|
| 4448 | AssertReleaseFailed(); /* No port I/O on ARM. */
|
---|
| 4449 | #else
|
---|
| 4450 | # error "I have no memory of this architecture"
|
---|
| 4451 | #endif
|
---|
| 4452 | }
|
---|
[75588] | 4453 | ASMCompilerBarrier(); /* paranoia */
|
---|
| 4454 | rc = fEvents != UINT32_MAX ? VINF_SUCCESS : VERR_INTERNAL_ERROR;
|
---|
| 4455 | }
|
---|
| 4456 | else
|
---|
| 4457 | {
|
---|
| 4458 | pReq->header.rc = VERR_INTERNAL_ERROR;
|
---|
| 4459 | pReq->events = 0;
|
---|
| 4460 | ASMCompilerBarrier();
|
---|
[100267] | 4461 | if (pDevExt->pMmioReq)
|
---|
| 4462 | *pDevExt->pMmioReq = pDevExt->PhysIrqAckEvents;
|
---|
| 4463 | else
|
---|
| 4464 | {
|
---|
| 4465 | #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
|
---|
| 4466 | ASMOutU32(pDevExt->IOPortBase + VMMDEV_PORT_OFF_REQUEST, (uint32_t)pDevExt->PhysIrqAckEvents);
|
---|
| 4467 | #elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
|
---|
| 4468 | AssertReleaseFailed();
|
---|
| 4469 | #else
|
---|
| 4470 | # error "I have no memory of this architecture"
|
---|
| 4471 | #endif
|
---|
| 4472 | }
|
---|
| 4473 |
|
---|
[75588] | 4474 | ASMCompilerBarrier(); /* paranoia */
|
---|
| 4475 | fEvents = pReq->events;
|
---|
| 4476 | rc = pReq->header.rc;
|
---|
| 4477 | }
|
---|
| 4478 | if (RT_SUCCESS(rc))
|
---|
| 4479 | {
|
---|
[58053] | 4480 | Log3(("VGDrvCommonISR: acknowledge events succeeded %#RX32\n", fEvents));
|
---|
[54237] | 4481 |
|
---|
[3657] | 4482 | /*
|
---|
[21376] | 4483 | * VMMDEV_EVENT_MOUSE_POSITION_CHANGED can only be polled for.
|
---|
[3657] | 4484 | */
|
---|
[21376] | 4485 | if (fEvents & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
|
---|
| 4486 | {
|
---|
[50537] | 4487 | fMousePositionChanged = true;
|
---|
| 4488 | fEvents &= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
|
---|
[68550] | 4489 | #if !defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT)
|
---|
[68561] | 4490 | if (pDevExt->pfnMouseNotifyCallback)
|
---|
| 4491 | pDevExt->pfnMouseNotifyCallback(pDevExt->pvMouseNotifyCallbackArg);
|
---|
[41649] | 4492 | #endif
|
---|
[21376] | 4493 | }
|
---|
[3657] | 4494 |
|
---|
[11820] | 4495 | #ifdef VBOX_WITH_HGCM
|
---|
[21376] | 4496 | /*
|
---|
| 4497 | * The HGCM event/list is kind of different in that we evaluate all entries.
|
---|
| 4498 | */
|
---|
[3657] | 4499 | if (fEvents & VMMDEV_EVENT_HGCM)
|
---|
[21376] | 4500 | {
|
---|
[56220] | 4501 | PVBOXGUESTWAIT pWait;
|
---|
| 4502 | PVBOXGUESTWAIT pSafe;
|
---|
[32449] | 4503 | RTListForEachSafe(&pDevExt->HGCMWaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
|
---|
| 4504 | {
|
---|
| 4505 | if (pWait->pHGCMReq->fu32Flags & VBOX_HGCM_REQ_DONE)
|
---|
[3657] | 4506 | {
|
---|
| 4507 | pWait->fResEvents = VMMDEV_EVENT_HGCM;
|
---|
[32449] | 4508 | RTListNodeRemove(&pWait->ListNode);
|
---|
| 4509 | # ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
|
---|
| 4510 | RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
|
---|
| 4511 | # else
|
---|
| 4512 | RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
|
---|
[21376] | 4513 | rc |= RTSemEventMultiSignal(pWait->Event);
|
---|
[32449] | 4514 | # endif
|
---|
[3657] | 4515 | }
|
---|
[32449] | 4516 | }
|
---|
[21376] | 4517 | fEvents &= ~VMMDEV_EVENT_HGCM;
|
---|
[21095] | 4518 | }
|
---|
| 4519 | #endif
|
---|
| 4520 |
|
---|
[21376] | 4521 | /*
|
---|
| 4522 | * Normal FIFO waiter evaluation.
|
---|
| 4523 | */
|
---|
[58053] | 4524 | rc |= vgdrvDispatchEventsLocked(pDevExt, fEvents);
|
---|
[3657] | 4525 | }
|
---|
| 4526 | else /* something is serious wrong... */
|
---|
[75588] | 4527 | Log(("VGDrvCommonISR: acknowledge events failed rc=%Rrc (events=%#x)!!\n", rc, fEvents));
|
---|
[3657] | 4528 | }
|
---|
| 4529 | else
|
---|
[58053] | 4530 | Log3(("VGDrvCommonISR: not ours\n"));
|
---|
[3657] | 4531 |
|
---|
[52618] | 4532 | RTSpinlockRelease(pDevExt->EventSpinlock);
|
---|
[32449] | 4533 |
|
---|
[64435] | 4534 | /*
|
---|
| 4535 | * Execute the mouse notification callback here if it cannot be executed while
|
---|
| 4536 | * holding the interrupt safe spinlock, see @bugref{8639}.
|
---|
| 4537 | */
|
---|
[68550] | 4538 | #if defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT) && !defined(RT_OS_WINDOWS) /* (Windows does this in the Dpc callback) */
|
---|
[64435] | 4539 | if ( fMousePositionChanged
|
---|
[68565] | 4540 | && pDevExt->pfnMouseNotifyCallback)
|
---|
| 4541 | pDevExt->pfnMouseNotifyCallback(pDevExt->pvMouseNotifyCallbackArg);
|
---|
[64435] | 4542 | #endif
|
---|
| 4543 |
|
---|
[75705] | 4544 | #if defined(VBOXGUEST_USE_DEFERRED_WAKE_UP) && !defined(RT_OS_WINDOWS)
|
---|
[21376] | 4545 | /*
|
---|
[32449] | 4546 | * Do wake-ups.
|
---|
| 4547 | * Note. On Windows this isn't possible at this IRQL, so a DPC will take
|
---|
[50688] | 4548 | * care of it. Same on darwin, doing it in the work loop callback.
|
---|
[21376] | 4549 | */
|
---|
[58053] | 4550 | VGDrvCommonWaitDoWakeUps(pDevExt);
|
---|
[22128] | 4551 | #endif
|
---|
[21376] | 4552 |
|
---|
[32449] | 4553 | /*
|
---|
| 4554 | * Work the poll and async notification queues on OSes that implements that.
|
---|
| 4555 | * (Do this outside the spinlock to prevent some recursive spinlocking.)
|
---|
| 4556 | */
|
---|
[21376] | 4557 | if (fMousePositionChanged)
|
---|
| 4558 | {
|
---|
| 4559 | ASMAtomicIncU32(&pDevExt->u32MousePosChangedSeq);
|
---|
[58053] | 4560 | VGDrvNativeISRMousePollEvent(pDevExt);
|
---|
[21376] | 4561 | }
|
---|
| 4562 |
|
---|
[75588] | 4563 | AssertMsg(rc == 0, ("rc=%#x (%d)\n", rc, rc));
|
---|
[3657] | 4564 | return fOurIrq;
|
---|
| 4565 | }
|
---|