1 /* $Id: VBoxGuest.cpp $ */
3 * VBoxGuest - Guest Additions Driver, Common Code.
7 * Copyright (C) 2007-2016 Oracle Corporation
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
27 /** @page pg_vbdrv VBoxGuest
29 * VBoxGuest is the device driver for VMMDev.
31 * The device driver is shipped as part of the guest additions. It has roots in
32 * the host VMM support driver (usually known as VBoxDrv), so fixes in platform
33 * specific code may apply to both drivers.
35 * The common code lives in VBoxGuest.cpp and is compiled both as C++ and C.
36 * The VBoxGuest.cpp source file shall not contain platform specific code,
37 * though it must occationally do a few \#ifdef RT_OS_XXX tests to cater for
38 * platform differences. Though, in those cases, it is common that more than
39 * one platform needs special handling.
41 * On most platforms the device driver should create two device nodes, one for
42 * full (unrestricted) access to the feature set, and one which only provides a
43 * restrict set of functions. These are generally referred to as 'vboxguest'
44 * and 'vboxuser' respectively. Currently, this two device approach is only
45 * implemented on Linux!
50 /*********************************************************************************************************************************
52 *********************************************************************************************************************************/
53 #define LOG_GROUP LOG_GROUP_DEFAULT
54 #include "VBoxGuestInternal.h"
55 #include <VBox/VMMDev.h> /* for VMMDEV_RAM_SIZE */
58 #include <iprt/time.h>
59 #include <iprt/memobj.h>
61 #include <iprt/asm-amd64-x86.h>
62 #include <iprt/string.h>
63 #include <iprt/process.h>
64 #include <iprt/assert.h>
65 #include <iprt/param.h>
66 #include <iprt/timer.h>
68 # include <iprt/thread.h>
70 #include "version-generated.h"
71 #if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
72 # include "revision-generated.h"
76 # include <iprt/win/windows.h>
79 #if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
80 # include <iprt/rand.h>
84 /*********************************************************************************************************************************
85 * Defined Constants And Macros *
86 *********************************************************************************************************************************/
87 #define VBOXGUEST_ACQUIRE_STYLE_EVENTS (VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
90 /*********************************************************************************************************************************
91 * Internal Functions *
92 *********************************************************************************************************************************/
94 static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallback(VMMDevHGCMRequestHeader
*pHdrNonVolatile
, void *pvUser
, uint32_t u32User
);
96 static int vgdrvIoCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
);
97 static void vgdrvBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker
);
98 static uint32_t vgdrvGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
);
99 static int vgdrvResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt
, uint32_t fFixedEvents
);
100 static int vgdrvResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt
);
101 static int vgdrvResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt
);
102 static int vgdrvSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
103 uint32_t fOrMask
, uint32_t fNotMask
, bool fSessionTermination
);
104 static int vgdrvSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
105 uint32_t fOrMask
, uint32_t fNotMask
, bool fSessionTermination
);
106 static int vgdrvSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
107 uint32_t fOrMask
, uint32_t fNoMask
, bool fSessionTermination
);
108 static int vgdrvAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, uint32_t fOrMask
,
109 uint32_t fNotMask
, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags
, bool fSessionTermination
);
110 static int vgdrvDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt
, uint32_t fEvents
);
113 /*********************************************************************************************************************************
115 *********************************************************************************************************************************/
116 static const uint32_t g_cbChangeMemBalloonReq
= RT_OFFSETOF(VMMDevChangeMemBalloon
, aPhysPage
[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
]);
118 #if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
120 * Drag in the rest of IRPT since we share it with the
121 * rest of the kernel modules on Solaris.
123 PFNRT g_apfnVBoxGuestIPRTDeps
[] =
128 (PFNRT
)RTSemMutexCreate
,
129 (PFNRT
)RTSemMutexDestroy
,
130 (PFNRT
)RTSemMutexRequest
,
131 (PFNRT
)RTSemMutexRequestNoResume
,
132 (PFNRT
)RTSemMutexRequestDebug
,
133 (PFNRT
)RTSemMutexRequestNoResumeDebug
,
134 (PFNRT
)RTSemMutexRelease
,
135 (PFNRT
)RTSemMutexIsOwned
,
138 #endif /* RT_OS_DARWIN || RT_OS_SOLARIS */
142 * Reserves memory in which the VMM can relocate any guest mappings
143 * that are floating around.
145 * This operation is a little bit tricky since the VMM might not accept
146 * just any address because of address clashes between the three contexts
147 * it operates in, so use a small stack to perform this operation.
149 * @returns VBox status code (ignored).
150 * @param pDevExt The device extension.
152 static int vgdrvInitFixateGuestMappings(PVBOXGUESTDEVEXT pDevExt
)
155 * Query the required space.
157 VMMDevReqHypervisorInfo
*pReq
;
158 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(VMMDevReqHypervisorInfo
), VMMDevReq_GetHypervisorInfo
);
161 pReq
->hypervisorStart
= 0;
162 pReq
->hypervisorSize
= 0;
163 rc
= VbglGRPerform(&pReq
->header
);
164 if (RT_FAILURE(rc
)) /* this shouldn't happen! */
166 VbglGRFree(&pReq
->header
);
171 * The VMM will report back if there is nothing it wants to map, like for
172 * instance in VT-x and AMD-V mode.
174 if (pReq
->hypervisorSize
== 0)
175 Log(("vgdrvInitFixateGuestMappings: nothing to do\n"));
179 * We have to try several times since the host can be picky
180 * about certain addresses.
182 RTR0MEMOBJ hFictive
= NIL_RTR0MEMOBJ
;
183 uint32_t cbHypervisor
= pReq
->hypervisorSize
;
184 RTR0MEMOBJ ahTries
[5];
186 bool fBitched
= false;
187 Log(("vgdrvInitFixateGuestMappings: cbHypervisor=%#x\n", cbHypervisor
));
188 for (iTry
= 0; iTry
< RT_ELEMENTS(ahTries
); iTry
++)
191 * Reserve space, or if that isn't supported, create a object for
192 * some fictive physical memory and map that in to kernel space.
194 * To make the code a bit uglier, most systems cannot help with
195 * 4MB alignment, so we have to deal with that in addition to
196 * having two ways of getting the memory.
198 uint32_t uAlignment
= _4M
;
200 rc
= RTR0MemObjReserveKernel(&hObj
, (void *)-1, RT_ALIGN_32(cbHypervisor
, _4M
), uAlignment
);
201 if (rc
== VERR_NOT_SUPPORTED
)
203 uAlignment
= PAGE_SIZE
;
204 rc
= RTR0MemObjReserveKernel(&hObj
, (void *)-1, RT_ALIGN_32(cbHypervisor
, _4M
) + _4M
, uAlignment
);
207 * If both RTR0MemObjReserveKernel calls above failed because either not supported or
208 * not implemented at all at the current platform, try to map the memory object into the
209 * virtual kernel space.
211 if (rc
== VERR_NOT_SUPPORTED
)
213 if (hFictive
== NIL_RTR0MEMOBJ
)
215 rc
= RTR0MemObjEnterPhys(&hObj
, VBOXGUEST_HYPERVISOR_PHYSICAL_START
, cbHypervisor
+ _4M
, RTMEM_CACHE_POLICY_DONT_CARE
);
221 rc
= RTR0MemObjMapKernel(&hObj
, hFictive
, (void *)-1, uAlignment
, RTMEM_PROT_READ
| RTMEM_PROT_WRITE
);
222 if (rc
== VERR_NOT_SUPPORTED
)
224 uAlignment
= PAGE_SIZE
;
225 rc
= RTR0MemObjMapKernel(&hObj
, hFictive
, (void *)-1, uAlignment
, RTMEM_PROT_READ
| RTMEM_PROT_WRITE
);
230 LogRel(("VBoxGuest: Failed to reserve memory for the hypervisor: rc=%Rrc (cbHypervisor=%#x uAlignment=%#x iTry=%u)\n",
231 rc
, cbHypervisor
, uAlignment
, iTry
));
239 pReq
->header
.requestType
= VMMDevReq_SetHypervisorInfo
;
240 pReq
->header
.rc
= VERR_INTERNAL_ERROR
;
241 pReq
->hypervisorSize
= cbHypervisor
;
242 pReq
->hypervisorStart
= (RTGCPTR32
)(uintptr_t)RTR0MemObjAddress(hObj
);
243 if ( uAlignment
== PAGE_SIZE
244 && pReq
->hypervisorStart
& (_4M
- 1))
245 pReq
->hypervisorStart
= RT_ALIGN_32(pReq
->hypervisorStart
, _4M
);
246 AssertMsg(RT_ALIGN_32(pReq
->hypervisorStart
, _4M
) == pReq
->hypervisorStart
, ("%#x\n", pReq
->hypervisorStart
));
248 rc
= VbglGRPerform(&pReq
->header
);
251 pDevExt
->hGuestMappings
= hFictive
!= NIL_RTR0MEMOBJ
? hFictive
: hObj
;
252 Log(("VBoxGuest: %p LB %#x; uAlignment=%#x iTry=%u hGuestMappings=%p (%s)\n",
253 RTR0MemObjAddress(pDevExt
->hGuestMappings
),
254 RTR0MemObjSize(pDevExt
->hGuestMappings
),
255 uAlignment
, iTry
, pDevExt
->hGuestMappings
, hFictive
!= NIL_RTR0PTR
? "fictive" : "reservation"));
258 ahTries
[iTry
] = hObj
;
262 * Cleanup failed attempts.
265 RTR0MemObjFree(ahTries
[iTry
], false /* fFreeMappings */);
267 && hFictive
!= NIL_RTR0PTR
)
268 RTR0MemObjFree(hFictive
, false /* fFreeMappings */);
269 if (RT_FAILURE(rc
) && !fBitched
)
270 LogRel(("VBoxGuest: Warning: failed to reserve %#d of memory for guest mappings.\n", cbHypervisor
));
272 VbglGRFree(&pReq
->header
);
275 * We ignore failed attempts for now.
282 * Undo what vgdrvInitFixateGuestMappings did.
284 * @param pDevExt The device extension.
286 static void vgdrvTermUnfixGuestMappings(PVBOXGUESTDEVEXT pDevExt
)
288 if (pDevExt
->hGuestMappings
!= NIL_RTR0PTR
)
291 * Tell the host that we're going to free the memory we reserved for
292 * it, the free it up. (Leak the memory if anything goes wrong here.)
294 VMMDevReqHypervisorInfo
*pReq
;
295 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(VMMDevReqHypervisorInfo
), VMMDevReq_SetHypervisorInfo
);
298 pReq
->hypervisorStart
= 0;
299 pReq
->hypervisorSize
= 0;
300 rc
= VbglGRPerform(&pReq
->header
);
301 VbglGRFree(&pReq
->header
);
305 rc
= RTR0MemObjFree(pDevExt
->hGuestMappings
, true /* fFreeMappings */);
309 LogRel(("vgdrvTermUnfixGuestMappings: Failed to unfix the guest mappings! rc=%Rrc\n", rc
));
311 pDevExt
->hGuestMappings
= NIL_RTR0MEMOBJ
;
318 * Report the guest information to the host.
320 * @returns IPRT status code.
321 * @param enmOSType The OS type to report.
323 static int vgdrvReportGuestInfo(VBOXOSTYPE enmOSType
)
326 * Allocate and fill in the two guest info reports.
328 VMMDevReportGuestInfo2
*pReqInfo2
= NULL
;
329 VMMDevReportGuestInfo
*pReqInfo1
= NULL
;
330 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReqInfo2
, sizeof (VMMDevReportGuestInfo2
), VMMDevReq_ReportGuestInfo2
);
331 Log(("vgdrvReportGuestInfo: VbglGRAlloc VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc
));
334 pReqInfo2
->guestInfo
.additionsMajor
= VBOX_VERSION_MAJOR
;
335 pReqInfo2
->guestInfo
.additionsMinor
= VBOX_VERSION_MINOR
;
336 pReqInfo2
->guestInfo
.additionsBuild
= VBOX_VERSION_BUILD
;
337 pReqInfo2
->guestInfo
.additionsRevision
= VBOX_SVN_REV
;
338 pReqInfo2
->guestInfo
.additionsFeatures
= 0; /* (no features defined yet) */
339 RTStrCopy(pReqInfo2
->guestInfo
.szName
, sizeof(pReqInfo2
->guestInfo
.szName
), VBOX_VERSION_STRING
);
341 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReqInfo1
, sizeof (VMMDevReportGuestInfo
), VMMDevReq_ReportGuestInfo
);
342 Log(("vgdrvReportGuestInfo: VbglGRAlloc VMMDevReportGuestInfo completed with rc=%Rrc\n", rc
));
345 pReqInfo1
->guestInfo
.interfaceVersion
= VMMDEV_VERSION
;
346 pReqInfo1
->guestInfo
.osType
= enmOSType
;
349 * There are two protocols here:
350 * 1. Info2 + Info1. Supported by >=3.2.51.
351 * 2. Info1 and optionally Info2. The old protocol.
353 * We try protocol 1 first. It will fail with VERR_NOT_SUPPORTED
354 * if not supported by the VMMDev (message ordering requirement).
356 rc
= VbglGRPerform(&pReqInfo2
->header
);
357 Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc
));
360 rc
= VbglGRPerform(&pReqInfo1
->header
);
361 Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo completed with rc=%Rrc\n", rc
));
363 else if ( rc
== VERR_NOT_SUPPORTED
364 || rc
== VERR_NOT_IMPLEMENTED
)
366 rc
= VbglGRPerform(&pReqInfo1
->header
);
367 Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo completed with rc=%Rrc\n", rc
));
370 rc
= VbglGRPerform(&pReqInfo2
->header
);
371 Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc
));
372 if (rc
== VERR_NOT_IMPLEMENTED
)
376 VbglGRFree(&pReqInfo1
->header
);
378 VbglGRFree(&pReqInfo2
->header
);
386 * Report the guest driver status to the host.
388 * @returns IPRT status code.
389 * @param fActive Flag whether the driver is now active or not.
391 static int vgdrvReportDriverStatus(bool fActive
)
394 * Report guest status of the VBox driver to the host.
396 VMMDevReportGuestStatus
*pReq2
= NULL
;
397 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq2
, sizeof(*pReq2
), VMMDevReq_ReportGuestStatus
);
398 Log(("vgdrvReportDriverStatus: VbglGRAlloc VMMDevReportGuestStatus completed with rc=%Rrc\n", rc
));
401 pReq2
->guestStatus
.facility
= VBoxGuestFacilityType_VBoxGuestDriver
;
402 pReq2
->guestStatus
.status
= fActive
?
403 VBoxGuestFacilityStatus_Active
404 : VBoxGuestFacilityStatus_Inactive
;
405 pReq2
->guestStatus
.flags
= 0;
406 rc
= VbglGRPerform(&pReq2
->header
);
407 Log(("vgdrvReportDriverStatus: VbglGRPerform VMMDevReportGuestStatus completed with fActive=%d, rc=%Rrc\n",
408 fActive
? 1 : 0, rc
));
409 if (rc
== VERR_NOT_IMPLEMENTED
) /* Compatibility with older hosts. */
411 VbglGRFree(&pReq2
->header
);
418 /** @name Memory Ballooning
423 * Inflate the balloon by one chunk represented by an R0 memory object.
425 * The caller owns the balloon mutex.
427 * @returns IPRT status code.
428 * @param pMemObj Pointer to the R0 memory object.
429 * @param pReq The pre-allocated request for performing the VMMDev call.
431 static int vgdrvBalloonInflate(PRTR0MEMOBJ pMemObj
, VMMDevChangeMemBalloon
*pReq
)
436 for (iPage
= 0; iPage
< VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
; iPage
++)
438 RTHCPHYS phys
= RTR0MemObjGetPagePhysAddr(*pMemObj
, iPage
);
439 pReq
->aPhysPage
[iPage
] = phys
;
442 pReq
->fInflate
= true;
443 pReq
->header
.size
= g_cbChangeMemBalloonReq
;
444 pReq
->cPages
= VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
;
446 rc
= VbglGRPerform(&pReq
->header
);
448 LogRel(("vgdrvBalloonInflate: VbglGRPerform failed. rc=%Rrc\n", rc
));
454 * Deflate the balloon by one chunk - info the host and free the memory object.
456 * The caller owns the balloon mutex.
458 * @returns IPRT status code.
459 * @param pMemObj Pointer to the R0 memory object.
460 * The memory object will be freed afterwards.
461 * @param pReq The pre-allocated request for performing the VMMDev call.
463 static int vgdrvBalloonDeflate(PRTR0MEMOBJ pMemObj
, VMMDevChangeMemBalloon
*pReq
)
468 for (iPage
= 0; iPage
< VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
; iPage
++)
470 RTHCPHYS phys
= RTR0MemObjGetPagePhysAddr(*pMemObj
, iPage
);
471 pReq
->aPhysPage
[iPage
] = phys
;
474 pReq
->fInflate
= false;
475 pReq
->header
.size
= g_cbChangeMemBalloonReq
;
476 pReq
->cPages
= VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
;
478 rc
= VbglGRPerform(&pReq
->header
);
481 LogRel(("vgdrvBalloonDeflate: VbglGRPerform failed. rc=%Rrc\n", rc
));
485 rc
= RTR0MemObjFree(*pMemObj
, true);
488 LogRel(("vgdrvBalloonDeflate: RTR0MemObjFree(%p,true) -> %Rrc; this is *BAD*!\n", *pMemObj
, rc
));
492 *pMemObj
= NIL_RTR0MEMOBJ
;
498 * Inflate/deflate the memory balloon and notify the host.
500 * This is a worker used by vgdrvIoCtl_CheckMemoryBalloon - it takes the mutex.
502 * @returns VBox status code.
503 * @param pDevExt The device extension.
504 * @param cBalloonChunks The new size of the balloon in chunks of 1MB.
505 * @param pfHandleInR3 Where to return the handle-in-ring3 indicator
506 * (VINF_SUCCESS if set).
508 static int vgdrvSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt
, uint32_t cBalloonChunks
, uint32_t *pfHandleInR3
)
510 int rc
= VINF_SUCCESS
;
512 if (pDevExt
->MemBalloon
.fUseKernelAPI
)
514 VMMDevChangeMemBalloon
*pReq
;
517 if (cBalloonChunks
> pDevExt
->MemBalloon
.cMaxChunks
)
519 LogRel(("vgdrvSetBalloonSizeKernel: illegal balloon size %u (max=%u)\n",
520 cBalloonChunks
, pDevExt
->MemBalloon
.cMaxChunks
));
521 return VERR_INVALID_PARAMETER
;
524 if (cBalloonChunks
== pDevExt
->MemBalloon
.cMaxChunks
)
525 return VINF_SUCCESS
; /* nothing to do */
527 if ( cBalloonChunks
> pDevExt
->MemBalloon
.cChunks
528 && !pDevExt
->MemBalloon
.paMemObj
)
530 pDevExt
->MemBalloon
.paMemObj
= (PRTR0MEMOBJ
)RTMemAllocZ(sizeof(RTR0MEMOBJ
) * pDevExt
->MemBalloon
.cMaxChunks
);
531 if (!pDevExt
->MemBalloon
.paMemObj
)
533 LogRel(("vgdrvSetBalloonSizeKernel: no memory for paMemObj!\n"));
534 return VERR_NO_MEMORY
;
538 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, g_cbChangeMemBalloonReq
, VMMDevReq_ChangeMemBalloon
);
542 if (cBalloonChunks
> pDevExt
->MemBalloon
.cChunks
)
545 for (i
= pDevExt
->MemBalloon
.cChunks
; i
< cBalloonChunks
; i
++)
547 rc
= RTR0MemObjAllocPhysNC(&pDevExt
->MemBalloon
.paMemObj
[i
],
548 VMMDEV_MEMORY_BALLOON_CHUNK_SIZE
, NIL_RTHCPHYS
);
551 if (rc
== VERR_NOT_SUPPORTED
)
553 /* not supported -- fall back to the R3-allocated memory. */
555 pDevExt
->MemBalloon
.fUseKernelAPI
= false;
556 Assert(pDevExt
->MemBalloon
.cChunks
== 0);
557 Log(("VBoxGuestSetBalloonSizeKernel: PhysNC allocs not supported, falling back to R3 allocs.\n"));
559 /* else if (rc == VERR_NO_MEMORY || rc == VERR_NO_PHYS_MEMORY):
560 * cannot allocate more memory => don't try further, just stop here */
561 /* else: XXX what else can fail? VERR_MEMOBJ_INIT_FAILED for instance. just stop. */
565 rc
= vgdrvBalloonInflate(&pDevExt
->MemBalloon
.paMemObj
[i
], pReq
);
568 Log(("vboxGuestSetBalloonSize(inflate): failed, rc=%Rrc!\n", rc
));
569 RTR0MemObjFree(pDevExt
->MemBalloon
.paMemObj
[i
], true);
570 pDevExt
->MemBalloon
.paMemObj
[i
] = NIL_RTR0MEMOBJ
;
573 pDevExt
->MemBalloon
.cChunks
++;
579 for (i
= pDevExt
->MemBalloon
.cChunks
; i
-- > cBalloonChunks
;)
581 rc
= vgdrvBalloonDeflate(&pDevExt
->MemBalloon
.paMemObj
[i
], pReq
);
584 Log(("vboxGuestSetBalloonSize(deflate): failed, rc=%Rrc!\n", rc
));
587 pDevExt
->MemBalloon
.cChunks
--;
591 VbglGRFree(&pReq
->header
);
595 * Set the handle-in-ring3 indicator. When set Ring-3 will have to work
596 * the balloon changes via the other API.
598 *pfHandleInR3
= pDevExt
->MemBalloon
.fUseKernelAPI
? false : true;
605 * Inflate/deflate the balloon by one chunk.
607 * Worker for vgdrvIoCtl_ChangeMemoryBalloon - it takes the mutex.
609 * @returns VBox status code.
610 * @param pDevExt The device extension.
611 * @param pSession The session.
612 * @param u64ChunkAddr The address of the chunk to add to / remove from the
614 * @param fInflate Inflate if true, deflate if false.
616 static int vgdrvSetBalloonSizeFromUser(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, uint64_t u64ChunkAddr
, bool fInflate
)
618 VMMDevChangeMemBalloon
*pReq
;
619 PRTR0MEMOBJ pMemObj
= NULL
;
620 int rc
= VINF_SUCCESS
;
626 if ( pDevExt
->MemBalloon
.cChunks
> pDevExt
->MemBalloon
.cMaxChunks
- 1
627 || pDevExt
->MemBalloon
.cMaxChunks
== 0 /* If called without first querying. */)
629 LogRel(("vboxGuestSetBalloonSize: cannot inflate balloon, already have %u chunks (max=%u)\n",
630 pDevExt
->MemBalloon
.cChunks
, pDevExt
->MemBalloon
.cMaxChunks
));
631 return VERR_INVALID_PARAMETER
;
634 if (!pDevExt
->MemBalloon
.paMemObj
)
636 pDevExt
->MemBalloon
.paMemObj
= (PRTR0MEMOBJ
)RTMemAlloc(sizeof(RTR0MEMOBJ
) * pDevExt
->MemBalloon
.cMaxChunks
);
637 if (!pDevExt
->MemBalloon
.paMemObj
)
639 LogRel(("VBoxGuestSetBalloonSizeFromUser: no memory for paMemObj!\n"));
640 return VERR_NO_MEMORY
;
642 for (i
= 0; i
< pDevExt
->MemBalloon
.cMaxChunks
; i
++)
643 pDevExt
->MemBalloon
.paMemObj
[i
] = NIL_RTR0MEMOBJ
;
648 if (pDevExt
->MemBalloon
.cChunks
== 0)
650 AssertMsgFailed(("vboxGuestSetBalloonSize: cannot decrease balloon, already at size 0\n"));
651 return VERR_INVALID_PARAMETER
;
656 * Enumerate all memory objects and check if the object is already registered.
658 for (i
= 0; i
< pDevExt
->MemBalloon
.cMaxChunks
; i
++)
662 && pDevExt
->MemBalloon
.paMemObj
[i
] == NIL_RTR0MEMOBJ
)
663 pMemObj
= &pDevExt
->MemBalloon
.paMemObj
[i
]; /* found free object pointer */
664 if (RTR0MemObjAddressR3(pDevExt
->MemBalloon
.paMemObj
[i
]) == u64ChunkAddr
)
667 return VERR_ALREADY_EXISTS
; /* don't provide the same memory twice */
668 pMemObj
= &pDevExt
->MemBalloon
.paMemObj
[i
];
676 /* no free object pointer found -- should not happen */
677 return VERR_NO_MEMORY
;
680 /* cannot free this memory as it wasn't provided before */
681 return VERR_NOT_FOUND
;
685 * Try inflate / default the balloon as requested.
687 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, g_cbChangeMemBalloonReq
, VMMDevReq_ChangeMemBalloon
);
693 rc
= RTR0MemObjLockUser(pMemObj
, (RTR3PTR
)u64ChunkAddr
, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE
,
694 RTMEM_PROT_READ
| RTMEM_PROT_WRITE
, NIL_RTR0PROCESS
);
697 rc
= vgdrvBalloonInflate(pMemObj
, pReq
);
699 pDevExt
->MemBalloon
.cChunks
++;
702 Log(("vboxGuestSetBalloonSize(inflate): failed, rc=%Rrc!\n", rc
));
703 RTR0MemObjFree(*pMemObj
, true);
704 *pMemObj
= NIL_RTR0MEMOBJ
;
710 rc
= vgdrvBalloonDeflate(pMemObj
, pReq
);
712 pDevExt
->MemBalloon
.cChunks
--;
714 Log(("vboxGuestSetBalloonSize(deflate): failed, rc=%Rrc!\n", rc
));
717 VbglGRFree(&pReq
->header
);
723 * Cleanup the memory balloon of a session.
725 * Will request the balloon mutex, so it must be valid and the caller must not
728 * @param pDevExt The device extension.
729 * @param pSession The session. Can be NULL at unload.
731 static void vgdrvCloseMemBalloon(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
)
733 RTSemFastMutexRequest(pDevExt
->MemBalloon
.hMtx
);
734 if ( pDevExt
->MemBalloon
.pOwner
== pSession
735 || pSession
== NULL
/*unload*/)
737 if (pDevExt
->MemBalloon
.paMemObj
)
739 VMMDevChangeMemBalloon
*pReq
;
740 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, g_cbChangeMemBalloonReq
, VMMDevReq_ChangeMemBalloon
);
744 for (i
= pDevExt
->MemBalloon
.cChunks
; i
-- > 0;)
746 rc
= vgdrvBalloonDeflate(&pDevExt
->MemBalloon
.paMemObj
[i
], pReq
);
749 LogRel(("vgdrvCloseMemBalloon: Deflate failed with rc=%Rrc. Will leak %u chunks.\n",
750 rc
, pDevExt
->MemBalloon
.cChunks
));
753 pDevExt
->MemBalloon
.paMemObj
[i
] = NIL_RTR0MEMOBJ
;
754 pDevExt
->MemBalloon
.cChunks
--;
756 VbglGRFree(&pReq
->header
);
759 LogRel(("vgdrvCloseMemBalloon: Failed to allocate VMMDev request buffer (rc=%Rrc). Will leak %u chunks.\n",
760 rc
, pDevExt
->MemBalloon
.cChunks
));
761 RTMemFree(pDevExt
->MemBalloon
.paMemObj
);
762 pDevExt
->MemBalloon
.paMemObj
= NULL
;
765 pDevExt
->MemBalloon
.pOwner
= NULL
;
767 RTSemFastMutexRelease(pDevExt
->MemBalloon
.hMtx
);
779 * Sends heartbeat to host.
781 * @returns VBox status code.
783 static int vgdrvHeartbeatSend(PVBOXGUESTDEVEXT pDevExt
)
786 if (pDevExt
->pReqGuestHeartbeat
)
788 rc
= VbglGRPerform(pDevExt
->pReqGuestHeartbeat
);
789 Log3(("vgdrvHeartbeatSend: VbglGRPerform vgdrvHeartbeatSend completed with rc=%Rrc\n", rc
));
792 rc
= VERR_INVALID_STATE
;
798 * Callback for heartbeat timer.
800 static DECLCALLBACK(void) vgdrvHeartbeatTimerHandler(PRTTIMER hTimer
, void *pvUser
, uint64_t iTick
)
802 PVBOXGUESTDEVEXT pDevExt
= (PVBOXGUESTDEVEXT
)pvUser
;
804 AssertReturnVoid(pDevExt
);
806 rc
= vgdrvHeartbeatSend(pDevExt
);
808 Log(("HB Timer: vgdrvHeartbeatSend failed: rc=%Rrc\n", rc
));
810 NOREF(hTimer
); NOREF(iTick
);
815 * Configure the host to check guest's heartbeat
816 * and get heartbeat interval from the host.
818 * @returns VBox status code.
819 * @param pDevExt The device extension.
820 * @param fEnabled Set true to enable guest heartbeat checks on host.
822 static int vgdrvHeartbeatHostConfigure(PVBOXGUESTDEVEXT pDevExt
, bool fEnabled
)
824 VMMDevReqHeartbeat
*pReq
;
825 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_HeartbeatConfigure
);
826 Log(("vgdrvHeartbeatHostConfigure: VbglGRAlloc vgdrvHeartbeatHostConfigure completed with rc=%Rrc\n", rc
));
829 pReq
->fEnabled
= fEnabled
;
830 pReq
->cNsInterval
= 0;
831 rc
= VbglGRPerform(&pReq
->header
);
832 Log(("vgdrvHeartbeatHostConfigure: VbglGRPerform vgdrvHeartbeatHostConfigure completed with rc=%Rrc\n", rc
));
833 pDevExt
->cNsHeartbeatInterval
= pReq
->cNsInterval
;
834 VbglGRFree(&pReq
->header
);
841 * Initializes the heartbeat timer.
843 * This feature may be disabled by the host.
845 * @returns VBox status (ignored).
846 * @param pDevExt The device extension.
848 static int vgdrvHeartbeatInit(PVBOXGUESTDEVEXT pDevExt
)
851 * Make sure that heartbeat checking is disabled.
853 int rc
= vgdrvHeartbeatHostConfigure(pDevExt
, false);
856 rc
= vgdrvHeartbeatHostConfigure(pDevExt
, true);
860 * Preallocate the request to use it from the timer callback because:
861 * 1) on Windows VbglGRAlloc must be called at IRQL <= APC_LEVEL
862 * and the timer callback runs at DISPATCH_LEVEL;
863 * 2) avoid repeated allocations.
865 rc
= VbglGRAlloc(&pDevExt
->pReqGuestHeartbeat
, sizeof(*pDevExt
->pReqGuestHeartbeat
), VMMDevReq_GuestHeartbeat
);
868 LogRel(("vgdrvHeartbeatInit: Setting up heartbeat to trigger every %RU64 milliseconds\n",
869 pDevExt
->cNsHeartbeatInterval
/ RT_NS_1MS
));
870 rc
= RTTimerCreateEx(&pDevExt
->pHeartbeatTimer
, pDevExt
->cNsHeartbeatInterval
, 0 /*fFlags*/,
871 (PFNRTTIMER
)vgdrvHeartbeatTimerHandler
, pDevExt
);
874 rc
= RTTimerStart(pDevExt
->pHeartbeatTimer
, 0);
878 LogRel(("vgdrvHeartbeatInit: Heartbeat timer failed to start, rc=%Rrc\n", rc
));
881 LogRel(("vgdrvHeartbeatInit: Failed to create heartbeat timer: %Rrc\n", rc
));
883 VbglGRFree(pDevExt
->pReqGuestHeartbeat
);
884 pDevExt
->pReqGuestHeartbeat
= NULL
;
887 LogRel(("vgdrvHeartbeatInit: VbglGRAlloc(VMMDevReq_GuestHeartbeat): %Rrc\n", rc
));
889 LogRel(("vgdrvHeartbeatInit: Failed to set up the timer, guest heartbeat is disabled\n"));
890 vgdrvHeartbeatHostConfigure(pDevExt
, false);
893 LogRel(("vgdrvHeartbeatInit: Failed to configure host for heartbeat checking: rc=%Rrc\n", rc
));
902 * Helper to reinit the VMMDev communication after hibernation.
904 * @returns VBox status code.
905 * @param pDevExt The device extension.
906 * @param enmOSType The OS type.
908 * @todo Call this on all platforms, not just windows.
910 int VGDrvCommonReinitDevExtAfterHibernation(PVBOXGUESTDEVEXT pDevExt
, VBOXOSTYPE enmOSType
)
912 int rc
= vgdrvReportGuestInfo(enmOSType
);
915 rc
= vgdrvReportDriverStatus(true /* Driver is active */);
917 Log(("VGDrvCommonReinitDevExtAfterHibernation: could not report guest driver status, rc=%Rrc\n", rc
));
920 Log(("VGDrvCommonReinitDevExtAfterHibernation: could not report guest information to host, rc=%Rrc\n", rc
));
921 LogFlow(("VGDrvCommonReinitDevExtAfterHibernation: returned with rc=%Rrc\n", rc
));
928 * Initializes the VBoxGuest device extension when the
929 * device driver is loaded.
931 * The native code locates the VMMDev on the PCI bus and retrieve
932 * the MMIO and I/O port ranges, this function will take care of
933 * mapping the MMIO memory (if present). Upon successful return
934 * the native code should set up the interrupt handler.
936 * @returns VBox status code.
938 * @param pDevExt The device extension. Allocated by the native code.
939 * @param IOPortBase The base of the I/O port range.
940 * @param pvMMIOBase The base of the MMIO memory mapping.
941 * This is optional, pass NULL if not present.
942 * @param cbMMIO The size of the MMIO memory mapping.
943 * This is optional, pass 0 if not present.
944 * @param enmOSType The guest OS type to report to the VMMDev.
945 * @param fFixedEvents Events that will be enabled upon init and no client
946 * will ever be allowed to mask.
948 int VGDrvCommonInitDevExt(PVBOXGUESTDEVEXT pDevExt
, uint16_t IOPortBase
,
949 void *pvMMIOBase
, uint32_t cbMMIO
, VBOXOSTYPE enmOSType
, uint32_t fFixedEvents
)
953 #ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
955 * Create the release log.
957 static const char * const s_apszGroups
[] = VBOX_LOGGROUP_NAMES
;
958 PRTLOGGER pRelLogger
;
959 rc
= RTLogCreate(&pRelLogger
, 0 /*fFlags*/, "all", "VBOXGUEST_RELEASE_LOG", RT_ELEMENTS(s_apszGroups
), s_apszGroups
,
960 RTLOGDEST_STDOUT
| RTLOGDEST_DEBUGGER
, NULL
);
962 RTLogRelSetDefaultInstance(pRelLogger
);
963 /** @todo Add native hook for getting logger config parameters and setting
964 * them. On linux we should use the module parameter stuff... */
968 * Adjust fFixedEvents.
970 #ifdef VBOX_WITH_HGCM
971 fFixedEvents
|= VMMDEV_EVENT_HGCM
;
975 * Initialize the data.
977 pDevExt
->IOPortBase
= IOPortBase
;
978 pDevExt
->pVMMDevMemory
= NULL
;
979 pDevExt
->hGuestMappings
= NIL_RTR0MEMOBJ
;
980 pDevExt
->EventSpinlock
= NIL_RTSPINLOCK
;
981 pDevExt
->pIrqAckEvents
= NULL
;
982 pDevExt
->PhysIrqAckEvents
= NIL_RTCCPHYS
;
983 RTListInit(&pDevExt
->WaitList
);
984 #ifdef VBOX_WITH_HGCM
985 RTListInit(&pDevExt
->HGCMWaitList
);
987 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
988 RTListInit(&pDevExt
->WakeUpList
);
990 RTListInit(&pDevExt
->WokenUpList
);
991 RTListInit(&pDevExt
->FreeList
);
992 RTListInit(&pDevExt
->SessionList
);
993 pDevExt
->cSessions
= 0;
994 pDevExt
->fLoggingEnabled
= false;
995 pDevExt
->f32PendingEvents
= 0;
996 pDevExt
->u32MousePosChangedSeq
= 0;
997 pDevExt
->SessionSpinlock
= NIL_RTSPINLOCK
;
998 pDevExt
->MemBalloon
.hMtx
= NIL_RTSEMFASTMUTEX
;
999 pDevExt
->MemBalloon
.cChunks
= 0;
1000 pDevExt
->MemBalloon
.cMaxChunks
= 0;
1001 pDevExt
->MemBalloon
.fUseKernelAPI
= true;
1002 pDevExt
->MemBalloon
.paMemObj
= NULL
;
1003 pDevExt
->MemBalloon
.pOwner
= NULL
;
1004 pDevExt
->MouseNotifyCallback
.pfnNotify
= NULL
;
1005 pDevExt
->MouseNotifyCallback
.pvUser
= NULL
;
1006 pDevExt
->pReqGuestHeartbeat
= NULL
;
1008 pDevExt
->fFixedEvents
= fFixedEvents
;
1009 vgdrvBitUsageTrackerClear(&pDevExt
->EventFilterTracker
);
1010 pDevExt
->fEventFilterHost
= UINT32_MAX
; /* forces a report */
1012 vgdrvBitUsageTrackerClear(&pDevExt
->MouseStatusTracker
);
1013 pDevExt
->fMouseStatusHost
= UINT32_MAX
; /* forces a report */
1015 pDevExt
->fAcquireModeGuestCaps
= 0;
1016 pDevExt
->fSetModeGuestCaps
= 0;
1017 pDevExt
->fAcquiredGuestCaps
= 0;
1018 vgdrvBitUsageTrackerClear(&pDevExt
->SetGuestCapsTracker
);
1019 pDevExt
->fGuestCapsHost
= UINT32_MAX
; /* forces a report */
1022 * If there is an MMIO region validate the version and size.
1026 VMMDevMemory
*pVMMDev
= (VMMDevMemory
*)pvMMIOBase
;
1028 if ( pVMMDev
->u32Version
== VMMDEV_MEMORY_VERSION
1029 && pVMMDev
->u32Size
>= 32
1030 && pVMMDev
->u32Size
<= cbMMIO
)
1032 pDevExt
->pVMMDevMemory
= pVMMDev
;
1033 Log(("VGDrvCommonInitDevExt: VMMDevMemory: mapping=%p size=%#RX32 (%#RX32) version=%#RX32\n",
1034 pVMMDev
, pVMMDev
->u32Size
, cbMMIO
, pVMMDev
->u32Version
));
1036 else /* try live without it. */
1037 LogRel(("VGDrvCommonInitDevExt: Bogus VMMDev memory; u32Version=%RX32 (expected %RX32) u32Size=%RX32 (expected <= %RX32)\n",
1038 pVMMDev
->u32Version
, VMMDEV_MEMORY_VERSION
, pVMMDev
->u32Size
, cbMMIO
));
1042 * Create the wait and session spinlocks as well as the ballooning mutex.
1044 rc
= RTSpinlockCreate(&pDevExt
->EventSpinlock
, RTSPINLOCK_FLAGS_INTERRUPT_SAFE
, "VBoxGuestEvent");
1046 rc
= RTSpinlockCreate(&pDevExt
->SessionSpinlock
, RTSPINLOCK_FLAGS_INTERRUPT_SAFE
, "VBoxGuestSession");
1049 LogRel(("VGDrvCommonInitDevExt: failed to create spinlock, rc=%Rrc!\n", rc
));
1050 if (pDevExt
->EventSpinlock
!= NIL_RTSPINLOCK
)
1051 RTSpinlockDestroy(pDevExt
->EventSpinlock
);
1055 rc
= RTSemFastMutexCreate(&pDevExt
->MemBalloon
.hMtx
);
1058 LogRel(("VGDrvCommonInitDevExt: failed to create mutex, rc=%Rrc!\n", rc
));
1059 RTSpinlockDestroy(pDevExt
->SessionSpinlock
);
1060 RTSpinlockDestroy(pDevExt
->EventSpinlock
);
1065 * Initialize the guest library and report the guest info back to VMMDev,
1066 * set the interrupt control filter mask, and fixate the guest mappings
1069 rc
= VbglInitPrimary(pDevExt
->IOPortBase
, (VMMDevMemory
*)pDevExt
->pVMMDevMemory
);
1072 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pDevExt
->pIrqAckEvents
, sizeof(VMMDevEvents
), VMMDevReq_AcknowledgeEvents
);
1075 pDevExt
->PhysIrqAckEvents
= VbglPhysHeapGetPhysAddr(pDevExt
->pIrqAckEvents
);
1076 Assert(pDevExt
->PhysIrqAckEvents
!= 0);
1078 rc
= vgdrvReportGuestInfo(enmOSType
);
1082 * Set the fixed event and make sure the host doesn't have any lingering
1083 * the guest capabilities or mouse status bits set.
1085 rc
= vgdrvResetEventFilterOnHost(pDevExt
, pDevExt
->fFixedEvents
);
1088 rc
= vgdrvResetCapabilitiesOnHost(pDevExt
);
1091 rc
= vgdrvResetMouseStatusOnHost(pDevExt
);
1095 * Initialize stuff which may fail without requiring the driver init to fail.
1097 vgdrvInitFixateGuestMappings(pDevExt
);
1098 vgdrvHeartbeatInit(pDevExt
);
1103 rc
= vgdrvReportDriverStatus(true /* Driver is active */);
1105 LogRel(("VGDrvCommonInitDevExt: VBoxReportGuestDriverStatus failed, rc=%Rrc\n", rc
));
1107 LogFlowFunc(("VGDrvCommonInitDevExt: returns success\n"));
1108 return VINF_SUCCESS
;
1110 LogRel(("VGDrvCommonInitDevExt: failed to clear mouse status: rc=%Rrc\n", rc
));
1113 LogRel(("VGDrvCommonInitDevExt: failed to clear guest capabilities: rc=%Rrc\n", rc
));
1116 LogRel(("VGDrvCommonInitDevExt: failed to set fixed event filter: rc=%Rrc\n", rc
));
1119 LogRel(("VGDrvCommonInitDevExt: VBoxReportGuestInfo failed: rc=%Rrc\n", rc
));
1120 VbglGRFree((VMMDevRequestHeader
*)pDevExt
->pIrqAckEvents
);
1123 LogRel(("VGDrvCommonInitDevExt: VBoxGRAlloc failed: rc=%Rrc\n", rc
));
1128 LogRel(("VGDrvCommonInitDevExt: VbglInit failed: rc=%Rrc\n", rc
));
1130 rc2
= RTSemFastMutexDestroy(pDevExt
->MemBalloon
.hMtx
); AssertRC(rc2
);
1131 rc2
= RTSpinlockDestroy(pDevExt
->EventSpinlock
); AssertRC(rc2
);
1132 rc2
= RTSpinlockDestroy(pDevExt
->SessionSpinlock
); AssertRC(rc2
);
1134 #ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
1135 RTLogDestroy(RTLogRelSetDefaultInstance(NULL
));
1136 RTLogDestroy(RTLogSetDefaultInstance(NULL
));
1138 return rc
; /* (failed) */
1143 * Deletes all the items in a wait chain.
1144 * @param pList The head of the chain.
1146 static void vgdrvDeleteWaitList(PRTLISTNODE pList
)
1148 while (!RTListIsEmpty(pList
))
1151 PVBOXGUESTWAIT pWait
= RTListGetFirst(pList
, VBOXGUESTWAIT
, ListNode
);
1152 RTListNodeRemove(&pWait
->ListNode
);
1154 rc2
= RTSemEventMultiDestroy(pWait
->Event
); AssertRC(rc2
);
1155 pWait
->Event
= NIL_RTSEMEVENTMULTI
;
1156 pWait
->pSession
= NULL
;
1163 * Destroys the VBoxGuest device extension.
1165 * The native code should call this before the driver is loaded,
1166 * but don't call this on shutdown.
1168 * @param pDevExt The device extension.
1170 void VGDrvCommonDeleteDevExt(PVBOXGUESTDEVEXT pDevExt
)
1173 Log(("VGDrvCommonDeleteDevExt:\n"));
1174 Log(("VBoxGuest: The additions driver is terminating.\n"));
1177 * Stop and destroy HB timer and
1178 * disable host heartbeat checking.
1180 if (pDevExt
->pHeartbeatTimer
)
1182 RTTimerDestroy(pDevExt
->pHeartbeatTimer
);
1183 vgdrvHeartbeatHostConfigure(pDevExt
, false);
1186 VbglGRFree(pDevExt
->pReqGuestHeartbeat
);
1187 pDevExt
->pReqGuestHeartbeat
= NULL
;
1190 * Clean up the bits that involves the host first.
1192 vgdrvTermUnfixGuestMappings(pDevExt
);
1193 if (!RTListIsEmpty(&pDevExt
->SessionList
))
1195 LogRelFunc(("session list not empty!\n"));
1196 RTListInit(&pDevExt
->SessionList
);
1198 /* Update the host flags (mouse status etc) not to reflect this session. */
1199 pDevExt
->fFixedEvents
= 0;
1200 vgdrvResetEventFilterOnHost(pDevExt
, 0 /*fFixedEvents*/);
1201 vgdrvResetCapabilitiesOnHost(pDevExt
);
1202 vgdrvResetMouseStatusOnHost(pDevExt
);
1204 vgdrvCloseMemBalloon(pDevExt
, (PVBOXGUESTSESSION
)NULL
);
1207 * Cleanup all the other resources.
1209 rc2
= RTSpinlockDestroy(pDevExt
->EventSpinlock
); AssertRC(rc2
);
1210 rc2
= RTSpinlockDestroy(pDevExt
->SessionSpinlock
); AssertRC(rc2
);
1211 rc2
= RTSemFastMutexDestroy(pDevExt
->MemBalloon
.hMtx
); AssertRC(rc2
);
1213 vgdrvDeleteWaitList(&pDevExt
->WaitList
);
1214 #ifdef VBOX_WITH_HGCM
1215 vgdrvDeleteWaitList(&pDevExt
->HGCMWaitList
);
1217 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
1218 vgdrvDeleteWaitList(&pDevExt
->WakeUpList
);
1220 vgdrvDeleteWaitList(&pDevExt
->WokenUpList
);
1221 vgdrvDeleteWaitList(&pDevExt
->FreeList
);
1225 pDevExt
->pVMMDevMemory
= NULL
;
1227 pDevExt
->IOPortBase
= 0;
1228 pDevExt
->pIrqAckEvents
= NULL
;
1230 #ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
1231 RTLogDestroy(RTLogRelSetDefaultInstance(NULL
));
1232 RTLogDestroy(RTLogSetDefaultInstance(NULL
));
1239 * Creates a VBoxGuest user session.
1241 * The native code calls this when a ring-3 client opens the device.
1242 * Use VGDrvCommonCreateKernelSession when a ring-0 client connects.
1244 * @returns VBox status code.
1245 * @param pDevExt The device extension.
1246 * @param ppSession Where to store the session on success.
1248 int VGDrvCommonCreateUserSession(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION
*ppSession
)
1250 PVBOXGUESTSESSION pSession
= (PVBOXGUESTSESSION
)RTMemAllocZ(sizeof(*pSession
));
1251 if (RT_UNLIKELY(!pSession
))
1253 LogRel(("VGDrvCommonCreateUserSession: no memory!\n"));
1254 return VERR_NO_MEMORY
;
1257 pSession
->Process
= RTProcSelf();
1258 pSession
->R0Process
= RTR0ProcHandleSelf();
1259 pSession
->pDevExt
= pDevExt
;
1260 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
1261 RTListAppend(&pDevExt
->SessionList
, &pSession
->ListNode
);
1262 pDevExt
->cSessions
++;
1263 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
1265 *ppSession
= pSession
;
1266 LogFlow(("VGDrvCommonCreateUserSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
1267 pSession
, pSession
->Process
, (int)pSession
->Process
, (uintptr_t)pSession
->R0Process
)); /** @todo %RTr0proc */
1268 return VINF_SUCCESS
;
1273 * Creates a VBoxGuest kernel session.
1275 * The native code calls this when a ring-0 client connects to the device.
1276 * Use VGDrvCommonCreateUserSession when a ring-3 client opens the device.
1278 * @returns VBox status code.
1279 * @param pDevExt The device extension.
1280 * @param ppSession Where to store the session on success.
1282 int VGDrvCommonCreateKernelSession(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION
*ppSession
)
1284 PVBOXGUESTSESSION pSession
= (PVBOXGUESTSESSION
)RTMemAllocZ(sizeof(*pSession
));
1285 if (RT_UNLIKELY(!pSession
))
1287 LogRel(("VGDrvCommonCreateKernelSession: no memory!\n"));
1288 return VERR_NO_MEMORY
;
1291 pSession
->Process
= NIL_RTPROCESS
;
1292 pSession
->R0Process
= NIL_RTR0PROCESS
;
1293 pSession
->pDevExt
= pDevExt
;
1294 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
1295 RTListAppend(&pDevExt
->SessionList
, &pSession
->ListNode
);
1296 pDevExt
->cSessions
++;
1297 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
1299 *ppSession
= pSession
;
1300 LogFlow(("VGDrvCommonCreateKernelSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
1301 pSession
, pSession
->Process
, (int)pSession
->Process
, (uintptr_t)pSession
->R0Process
)); /** @todo %RTr0proc */
1302 return VINF_SUCCESS
;
1307 * Closes a VBoxGuest session.
1309 * @param pDevExt The device extension.
1310 * @param pSession The session to close (and free).
1312 void VGDrvCommonCloseSession(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
)
1314 #ifdef VBOX_WITH_HGCM
1317 LogFlow(("VGDrvCommonCloseSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
1318 pSession
, pSession
->Process
, (int)pSession
->Process
, (uintptr_t)pSession
->R0Process
)); /** @todo %RTr0proc */
1320 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
1321 RTListNodeRemove(&pSession
->ListNode
);
1322 pDevExt
->cSessions
--;
1323 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
1324 vgdrvAcquireSessionCapabilities(pDevExt
, pSession
, 0, UINT32_MAX
, VBOXGUESTCAPSACQUIRE_FLAGS_NONE
,
1325 true /*fSessionTermination*/);
1326 vgdrvSetSessionCapabilities(pDevExt
, pSession
, 0 /*fOrMask*/, UINT32_MAX
/*fNotMask*/, true /*fSessionTermination*/);
1327 vgdrvSetSessionEventFilter(pDevExt
, pSession
, 0 /*fOrMask*/, UINT32_MAX
/*fNotMask*/, true /*fSessionTermination*/);
1328 vgdrvSetSessionMouseStatus(pDevExt
, pSession
, 0 /*fOrMask*/, UINT32_MAX
/*fNotMask*/, true /*fSessionTermination*/);
1330 vgdrvIoCtl_CancelAllWaitEvents(pDevExt
, pSession
);
1332 #ifdef VBOX_WITH_HGCM
1333 for (i
= 0; i
< RT_ELEMENTS(pSession
->aHGCMClientIds
); i
++)
1334 if (pSession
->aHGCMClientIds
[i
])
1336 VBoxGuestHGCMDisconnectInfo Info
;
1338 Info
.u32ClientID
= pSession
->aHGCMClientIds
[i
];
1339 pSession
->aHGCMClientIds
[i
] = 0;
1340 Log(("VGDrvCommonCloseSession: disconnecting client id %#RX32\n", Info
.u32ClientID
));
1341 VbglR0HGCMInternalDisconnect(&Info
, vgdrvHgcmAsyncWaitCallback
, pDevExt
, RT_INDEFINITE_WAIT
);
1345 pSession
->pDevExt
= NULL
;
1346 pSession
->Process
= NIL_RTPROCESS
;
1347 pSession
->R0Process
= NIL_RTR0PROCESS
;
1348 vgdrvCloseMemBalloon(pDevExt
, pSession
);
1349 RTMemFree(pSession
);
1354 * Allocates a wait-for-event entry.
1356 * @returns The wait-for-event entry.
1357 * @param pDevExt The device extension.
1358 * @param pSession The session that's allocating this. Can be NULL.
1360 static PVBOXGUESTWAIT
vgdrvWaitAlloc(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
)
1363 * Allocate it one way or the other.
1365 PVBOXGUESTWAIT pWait
= RTListGetFirst(&pDevExt
->FreeList
, VBOXGUESTWAIT
, ListNode
);
1368 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1370 pWait
= RTListGetFirst(&pDevExt
->FreeList
, VBOXGUESTWAIT
, ListNode
);
1372 RTListNodeRemove(&pWait
->ListNode
);
1374 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1380 pWait
= (PVBOXGUESTWAIT
)RTMemAlloc(sizeof(*pWait
));
1383 LogRelMax(32, ("vgdrvWaitAlloc: out-of-memory!\n"));
1387 rc
= RTSemEventMultiCreate(&pWait
->Event
);
1390 LogRelMax(32, ("vgdrvWaitAlloc: RTSemEventMultiCreate failed with rc=%Rrc!\n", rc
));
1395 pWait
->ListNode
.pNext
= NULL
;
1396 pWait
->ListNode
.pPrev
= NULL
;
1400 * Zero members just as an precaution.
1402 pWait
->fReqEvents
= 0;
1403 pWait
->fResEvents
= 0;
1404 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
1405 pWait
->fPendingWakeUp
= false;
1406 pWait
->fFreeMe
= false;
1408 pWait
->pSession
= pSession
;
1409 #ifdef VBOX_WITH_HGCM
1410 pWait
->pHGCMReq
= NULL
;
1412 RTSemEventMultiReset(pWait
->Event
);
1418 * Frees the wait-for-event entry.
1420 * The caller must own the wait spinlock !
1421 * The entry must be in a list!
1423 * @param pDevExt The device extension.
1424 * @param pWait The wait-for-event entry to free.
1426 static void vgdrvWaitFreeLocked(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTWAIT pWait
)
1428 pWait
->fReqEvents
= 0;
1429 pWait
->fResEvents
= 0;
1430 #ifdef VBOX_WITH_HGCM
1431 pWait
->pHGCMReq
= NULL
;
1433 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
1434 Assert(!pWait
->fFreeMe
);
1435 if (pWait
->fPendingWakeUp
)
1436 pWait
->fFreeMe
= true;
1440 RTListNodeRemove(&pWait
->ListNode
);
1441 RTListAppend(&pDevExt
->FreeList
, &pWait
->ListNode
);
1447 * Frees the wait-for-event entry.
1449 * @param pDevExt The device extension.
1450 * @param pWait The wait-for-event entry to free.
1452 static void vgdrvWaitFreeUnlocked(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTWAIT pWait
)
1454 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1455 vgdrvWaitFreeLocked(pDevExt
, pWait
);
1456 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1460 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
1462 * Processes the wake-up list.
1464 * All entries in the wake-up list gets signalled and moved to the woken-up
1466 * At least on Windows this function can be invoked concurrently from
1467 * different VCPUs. So, be thread-safe.
1469 * @param pDevExt The device extension.
1471 void VGDrvCommonWaitDoWakeUps(PVBOXGUESTDEVEXT pDevExt
)
1473 if (!RTListIsEmpty(&pDevExt
->WakeUpList
))
1475 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1479 PVBOXGUESTWAIT pWait
= RTListGetFirst(&pDevExt
->WakeUpList
, VBOXGUESTWAIT
, ListNode
);
1482 /* Prevent other threads from accessing pWait when spinlock is released. */
1483 RTListNodeRemove(&pWait
->ListNode
);
1485 pWait
->fPendingWakeUp
= true;
1486 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1488 rc
= RTSemEventMultiSignal(pWait
->Event
);
1491 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1492 Assert(pWait
->ListNode
.pNext
== NULL
&& pWait
->ListNode
.pPrev
== NULL
);
1493 RTListAppend(&pDevExt
->WokenUpList
, &pWait
->ListNode
);
1494 pWait
->fPendingWakeUp
= false;
1495 if (RT_LIKELY(!pWait
->fFreeMe
))
1499 pWait
->fFreeMe
= false;
1500 vgdrvWaitFreeLocked(pDevExt
, pWait
);
1503 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1506 #endif /* VBOXGUEST_USE_DEFERRED_WAKE_UP */
1510 * Implements the fast (no input or output) type of IOCtls.
1512 * This is currently just a placeholder stub inherited from the support driver code.
1514 * @returns VBox status code.
1515 * @param iFunction The IOCtl function number.
1516 * @param pDevExt The device extension.
1517 * @param pSession The session.
1519 int VGDrvCommonIoCtlFast(unsigned iFunction
, PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
)
1521 LogFlow(("VGDrvCommonIoCtlFast: iFunction=%#x pDevExt=%p pSession=%p\n", iFunction
, pDevExt
, pSession
));
1526 return VERR_NOT_SUPPORTED
;
1531 * Return the VMM device port.
1533 * returns IPRT status code.
1534 * @param pDevExt The device extension.
1535 * @param pInfo The request info.
1536 * @param pcbDataReturned (out) contains the number of bytes to return.
1538 static int vgdrvIoCtl_GetVMMDevPort(PVBOXGUESTDEVEXT pDevExt
, VBoxGuestPortInfo
*pInfo
, size_t *pcbDataReturned
)
1540 LogFlow(("VBOXGUEST_IOCTL_GETVMMDEVPORT\n"));
1542 pInfo
->portAddress
= pDevExt
->IOPortBase
;
1543 pInfo
->pVMMDevMemory
= (VMMDevMemory
*)pDevExt
->pVMMDevMemory
;
1544 if (pcbDataReturned
)
1545 *pcbDataReturned
= sizeof(*pInfo
);
1546 return VINF_SUCCESS
;
1550 #ifndef RT_OS_WINDOWS
1552 * Set the callback for the kernel mouse handler.
1554 * returns IPRT status code.
1555 * @param pDevExt The device extension.
1556 * @param pNotify The new callback information.
1558 int vgdrvIoCtl_SetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt
, VBoxGuestMouseSetNotifyCallback
*pNotify
)
1560 LogFlow(("VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK: pfnNotify=%p pvUser=%p\n", pNotify
->pfnNotify
, pNotify
->pvUser
));
1562 #ifdef VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
1563 VGDrvNativeSetMouseNotifyCallback(pDevExt
, pNotify
);
1565 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1566 pDevExt
->MouseNotifyCallback
= *pNotify
;
1567 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1569 return VINF_SUCCESS
;
1575 * Worker vgdrvIoCtl_WaitEvent.
1577 * The caller enters the spinlock, we leave it.
1579 * @returns VINF_SUCCESS if we've left the spinlock and can return immediately.
1581 DECLINLINE(int) vbdgCheckWaitEventCondition(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
1582 VBoxGuestWaitEventInfo
*pInfo
, int iEvent
, const uint32_t fReqEvents
)
1584 uint32_t fMatches
= pDevExt
->f32PendingEvents
& fReqEvents
;
1585 if (fMatches
& VBOXGUEST_ACQUIRE_STYLE_EVENTS
)
1586 fMatches
&= vgdrvGetAllowedEventMaskForSession(pDevExt
, pSession
);
1587 if (fMatches
|| pSession
->fPendingCancelWaitEvents
)
1589 ASMAtomicAndU32(&pDevExt
->f32PendingEvents
, ~fMatches
);
1590 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1592 pInfo
->u32EventFlagsOut
= fMatches
;
1593 pInfo
->u32Result
= VBOXGUEST_WAITEVENT_OK
;
1594 if (fReqEvents
& ~((uint32_t)1 << iEvent
))
1595 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x\n", pInfo
->u32EventFlagsOut
));
1597 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x/%d\n", pInfo
->u32EventFlagsOut
, iEvent
));
1598 pSession
->fPendingCancelWaitEvents
= false;
1599 return VINF_SUCCESS
;
1602 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1603 return VERR_TIMEOUT
;
1607 static int vgdrvIoCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
1608 VBoxGuestWaitEventInfo
*pInfo
, size_t *pcbDataReturned
, bool fInterruptible
)
1610 const uint32_t fReqEvents
= pInfo
->u32EventMaskIn
;
1611 uint32_t fResEvents
;
1613 PVBOXGUESTWAIT pWait
;
1616 pInfo
->u32EventFlagsOut
= 0;
1617 pInfo
->u32Result
= VBOXGUEST_WAITEVENT_ERROR
;
1618 if (pcbDataReturned
)
1619 *pcbDataReturned
= sizeof(*pInfo
);
1622 * Copy and verify the input mask.
1624 iEvent
= ASMBitFirstSetU32(fReqEvents
) - 1;
1625 if (RT_UNLIKELY(iEvent
< 0))
1627 LogRel(("VBOXGUEST_IOCTL_WAITEVENT: Invalid input mask %#x!!\n", fReqEvents
));
1628 return VERR_INVALID_PARAMETER
;
1632 * Check the condition up front, before doing the wait-for-event allocations.
1634 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1635 rc
= vbdgCheckWaitEventCondition(pDevExt
, pSession
, pInfo
, iEvent
, fReqEvents
);
1636 if (rc
== VINF_SUCCESS
)
1639 if (!pInfo
->u32TimeoutIn
)
1641 pInfo
->u32Result
= VBOXGUEST_WAITEVENT_TIMEOUT
;
1642 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_TIMEOUT\n"));
1643 return VERR_TIMEOUT
;
1646 pWait
= vgdrvWaitAlloc(pDevExt
, pSession
);
1648 return VERR_NO_MEMORY
;
1649 pWait
->fReqEvents
= fReqEvents
;
1652 * We've got the wait entry now, re-enter the spinlock and check for the condition.
1653 * If the wait condition is met, return.
1654 * Otherwise enter into the list and go to sleep waiting for the ISR to signal us.
1656 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1657 RTListAppend(&pDevExt
->WaitList
, &pWait
->ListNode
);
1658 rc
= vbdgCheckWaitEventCondition(pDevExt
, pSession
, pInfo
, iEvent
, fReqEvents
);
1659 if (rc
== VINF_SUCCESS
)
1661 vgdrvWaitFreeUnlocked(pDevExt
, pWait
);
1666 rc
= RTSemEventMultiWaitNoResume(pWait
->Event
,
1667 pInfo
->u32TimeoutIn
== UINT32_MAX
? RT_INDEFINITE_WAIT
: pInfo
->u32TimeoutIn
);
1669 rc
= RTSemEventMultiWait(pWait
->Event
,
1670 pInfo
->u32TimeoutIn
== UINT32_MAX
? RT_INDEFINITE_WAIT
: pInfo
->u32TimeoutIn
);
1673 * There is one special case here and that's when the semaphore is
1674 * destroyed upon device driver unload. This shouldn't happen of course,
1675 * but in case it does, just get out of here ASAP.
1677 if (rc
== VERR_SEM_DESTROYED
)
1681 * Unlink the wait item and dispose of it.
1683 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1684 fResEvents
= pWait
->fResEvents
;
1685 vgdrvWaitFreeLocked(pDevExt
, pWait
);
1686 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1689 * Now deal with the return code.
1692 && fResEvents
!= UINT32_MAX
)
1694 pInfo
->u32EventFlagsOut
= fResEvents
;
1695 pInfo
->u32Result
= VBOXGUEST_WAITEVENT_OK
;
1696 if (fReqEvents
& ~((uint32_t)1 << iEvent
))
1697 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x\n", pInfo
->u32EventFlagsOut
));
1699 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x/%d\n", pInfo
->u32EventFlagsOut
, iEvent
));
1702 else if ( fResEvents
== UINT32_MAX
1703 || rc
== VERR_INTERRUPTED
)
1705 pInfo
->u32Result
= VBOXGUEST_WAITEVENT_INTERRUPTED
;
1706 rc
= VERR_INTERRUPTED
;
1707 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_INTERRUPTED\n"));
1709 else if (rc
== VERR_TIMEOUT
)
1711 pInfo
->u32Result
= VBOXGUEST_WAITEVENT_TIMEOUT
;
1712 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_TIMEOUT (2)\n"));
1718 LogRelMax(32, ("VBOXGUEST_IOCTL_WAITEVENT: returns %Rrc but no events!\n", rc
));
1719 rc
= VERR_INTERNAL_ERROR
;
1721 pInfo
->u32Result
= VBOXGUEST_WAITEVENT_ERROR
;
1722 LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %Rrc\n", rc
));
1729 static int vgdrvIoCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
)
1731 PVBOXGUESTWAIT pWait
;
1732 PVBOXGUESTWAIT pSafe
;
1734 /* Was as least one WAITEVENT in process for this session? If not we
1735 * set a flag that the next call should be interrupted immediately. This
1736 * is needed so that a user thread can reliably interrupt another one in a
1737 * WAITEVENT loop. */
1738 bool fCancelledOne
= false;
1740 LogFlow(("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS\n"));
1743 * Walk the event list and wake up anyone with a matching session.
1745 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
1746 RTListForEachSafe(&pDevExt
->WaitList
, pWait
, pSafe
, VBOXGUESTWAIT
, ListNode
)
1748 if (pWait
->pSession
== pSession
)
1750 fCancelledOne
= true;
1751 pWait
->fResEvents
= UINT32_MAX
;
1752 RTListNodeRemove(&pWait
->ListNode
);
1753 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
1754 RTListAppend(&pDevExt
->WakeUpList
, &pWait
->ListNode
);
1756 rc
|= RTSemEventMultiSignal(pWait
->Event
);
1757 RTListAppend(&pDevExt
->WokenUpList
, &pWait
->ListNode
);
1762 pSession
->fPendingCancelWaitEvents
= true;
1763 RTSpinlockRelease(pDevExt
->EventSpinlock
);
1767 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
1768 VGDrvCommonWaitDoWakeUps(pDevExt
);
1771 return VINF_SUCCESS
;
1776 * Checks if the VMM request is allowed in the context of the given session.
1778 * @returns VINF_SUCCESS or VERR_PERMISSION_DENIED.
1779 * @param pDevExt The device extension.
1780 * @param pSession The calling session.
1781 * @param enmType The request type.
1782 * @param pReqHdr The request.
1784 static int vgdrvCheckIfVmmReqIsAllowed(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, VMMDevRequestType enmType
,
1785 VMMDevRequestHeader
const *pReqHdr
)
1788 * Categorize the request being made.
1790 /** @todo This need quite some more work! */
1793 kLevel_Invalid
, kLevel_NoOne
, kLevel_OnlyVBoxGuest
, kLevel_OnlyKernel
, kLevel_TrustedUsers
, kLevel_AllUsers
1800 * Deny access to anything we don't know or provide specialized I/O controls for.
1802 #ifdef VBOX_WITH_HGCM
1803 case VMMDevReq_HGCMConnect
:
1804 case VMMDevReq_HGCMDisconnect
:
1805 # ifdef VBOX_WITH_64_BITS_GUESTS
1806 case VMMDevReq_HGCMCall32
:
1807 case VMMDevReq_HGCMCall64
:
1809 case VMMDevReq_HGCMCall
:
1810 # endif /* VBOX_WITH_64_BITS_GUESTS */
1811 case VMMDevReq_HGCMCancel
:
1812 case VMMDevReq_HGCMCancel2
:
1813 #endif /* VBOX_WITH_HGCM */
1814 case VMMDevReq_SetGuestCapabilities
:
1816 enmRequired
= kLevel_NoOne
;
1820 * There are a few things only this driver can do (and it doesn't use
1821 * the VMMRequst I/O control route anyway, but whatever).
1823 case VMMDevReq_ReportGuestInfo
:
1824 case VMMDevReq_ReportGuestInfo2
:
1825 case VMMDevReq_GetHypervisorInfo
:
1826 case VMMDevReq_SetHypervisorInfo
:
1827 case VMMDevReq_RegisterPatchMemory
:
1828 case VMMDevReq_DeregisterPatchMemory
:
1829 case VMMDevReq_GetMemBalloonChangeRequest
:
1830 enmRequired
= kLevel_OnlyVBoxGuest
;
1834 * Trusted users apps only.
1836 case VMMDevReq_QueryCredentials
:
1837 case VMMDevReq_ReportCredentialsJudgement
:
1838 case VMMDevReq_RegisterSharedModule
:
1839 case VMMDevReq_UnregisterSharedModule
:
1840 case VMMDevReq_WriteCoreDump
:
1841 case VMMDevReq_GetCpuHotPlugRequest
:
1842 case VMMDevReq_SetCpuHotPlugStatus
:
1843 case VMMDevReq_CheckSharedModules
:
1844 case VMMDevReq_GetPageSharingStatus
:
1845 case VMMDevReq_DebugIsPageShared
:
1846 case VMMDevReq_ReportGuestStats
:
1847 case VMMDevReq_ReportGuestUserState
:
1848 case VMMDevReq_GetStatisticsChangeRequest
:
1849 case VMMDevReq_ChangeMemBalloon
:
1850 enmRequired
= kLevel_TrustedUsers
;
1856 case VMMDevReq_GetMouseStatus
:
1857 case VMMDevReq_SetMouseStatus
:
1858 case VMMDevReq_SetPointerShape
:
1859 case VMMDevReq_GetHostVersion
:
1860 case VMMDevReq_Idle
:
1861 case VMMDevReq_GetHostTime
:
1862 case VMMDevReq_SetPowerStatus
:
1863 case VMMDevReq_AcknowledgeEvents
:
1864 case VMMDevReq_CtlGuestFilterMask
:
1865 case VMMDevReq_ReportGuestStatus
:
1866 case VMMDevReq_GetDisplayChangeRequest
:
1867 case VMMDevReq_VideoModeSupported
:
1868 case VMMDevReq_GetHeightReduction
:
1869 case VMMDevReq_GetDisplayChangeRequest2
:
1870 case VMMDevReq_VideoModeSupported2
:
1871 case VMMDevReq_VideoAccelEnable
:
1872 case VMMDevReq_VideoAccelFlush
:
1873 case VMMDevReq_VideoSetVisibleRegion
:
1874 case VMMDevReq_GetDisplayChangeRequestEx
:
1875 case VMMDevReq_GetSeamlessChangeRequest
:
1876 case VMMDevReq_GetVRDPChangeRequest
:
1877 case VMMDevReq_LogString
:
1878 case VMMDevReq_GetSessionId
:
1879 enmRequired
= kLevel_AllUsers
;
1883 * Depends on the request parameters...
1885 /** @todo this have to be changed into an I/O control and the facilities
1886 * tracked in the session so they can automatically be failed when the
1887 * session terminates without reporting the new status.
1889 * The information presented by IGuest is not reliable without this! */
1890 case VMMDevReq_ReportGuestCapabilities
:
1891 switch (((VMMDevReportGuestStatus
const *)pReqHdr
)->guestStatus
.facility
)
1893 case VBoxGuestFacilityType_All
:
1894 case VBoxGuestFacilityType_VBoxGuestDriver
:
1895 enmRequired
= kLevel_OnlyVBoxGuest
;
1897 case VBoxGuestFacilityType_VBoxService
:
1898 enmRequired
= kLevel_TrustedUsers
;
1900 case VBoxGuestFacilityType_VBoxTrayClient
:
1901 case VBoxGuestFacilityType_Seamless
:
1902 case VBoxGuestFacilityType_Graphics
:
1904 enmRequired
= kLevel_AllUsers
;
1911 * Check against the session.
1913 switch (enmRequired
)
1918 case kLevel_OnlyVBoxGuest
:
1919 case kLevel_OnlyKernel
:
1920 if (pSession
->R0Process
== NIL_RTR0PROCESS
)
1921 return VINF_SUCCESS
;
1923 case kLevel_TrustedUsers
:
1924 case kLevel_AllUsers
:
1925 return VINF_SUCCESS
;
1928 return VERR_PERMISSION_DENIED
;
1931 static int vgdrvIoCtl_VMMRequest(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
1932 VMMDevRequestHeader
*pReqHdr
, size_t cbData
, size_t *pcbDataReturned
)
1935 VMMDevRequestHeader
*pReqCopy
;
1938 * Validate the header and request size.
1940 const VMMDevRequestType enmType
= pReqHdr
->requestType
;
1941 const uint32_t cbReq
= pReqHdr
->size
;
1942 const uint32_t cbMinSize
= (uint32_t)vmmdevGetRequestSize(enmType
);
1944 LogFlow(("VBOXGUEST_IOCTL_VMMREQUEST: type %d\n", pReqHdr
->requestType
));
1946 if (cbReq
< cbMinSize
)
1948 LogRel(("VBOXGUEST_IOCTL_VMMREQUEST: invalid hdr size %#x, expected >= %#x; type=%#x!!\n",
1949 cbReq
, cbMinSize
, enmType
));
1950 return VERR_INVALID_PARAMETER
;
1954 LogRel(("VBOXGUEST_IOCTL_VMMREQUEST: invalid size %#x, expected >= %#x (hdr); type=%#x!!\n",
1955 cbData
, cbReq
, enmType
));
1956 return VERR_INVALID_PARAMETER
;
1958 rc
= VbglGRVerify(pReqHdr
, cbData
);
1961 Log(("VBOXGUEST_IOCTL_VMMREQUEST: invalid header: size %#x, expected >= %#x (hdr); type=%#x; rc=%Rrc!!\n",
1962 cbData
, cbReq
, enmType
, rc
));
1966 rc
= vgdrvCheckIfVmmReqIsAllowed(pDevExt
, pSession
, enmType
, pReqHdr
);
1969 Log(("VBOXGUEST_IOCTL_VMMREQUEST: Operation not allowed! type=%#x rc=%Rrc\n", enmType
, rc
));
1974 * Make a copy of the request in the physical memory heap so
1975 * the VBoxGuestLibrary can more easily deal with the request.
1976 * (This is really a waste of time since the OS or the OS specific
1977 * code has already buffered or locked the input/output buffer, but
1978 * it does makes things a bit simpler wrt to phys address.)
1980 rc
= VbglGRAlloc(&pReqCopy
, cbReq
, enmType
);
1983 Log(("VBOXGUEST_IOCTL_VMMREQUEST: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
1987 memcpy(pReqCopy
, pReqHdr
, cbReq
);
1989 if (enmType
== VMMDevReq_GetMouseStatus
) /* clear poll condition. */
1990 pSession
->u32MousePosChangedSeq
= ASMAtomicUoReadU32(&pDevExt
->u32MousePosChangedSeq
);
1992 rc
= VbglGRPerform(pReqCopy
);
1994 && RT_SUCCESS(pReqCopy
->rc
))
1996 Assert(rc
!= VINF_HGCM_ASYNC_EXECUTE
);
1997 Assert(pReqCopy
->rc
!= VINF_HGCM_ASYNC_EXECUTE
);
1999 memcpy(pReqHdr
, pReqCopy
, cbReq
);
2000 if (pcbDataReturned
)
2001 *pcbDataReturned
= cbReq
;
2003 else if (RT_FAILURE(rc
))
2004 Log(("VBOXGUEST_IOCTL_VMMREQUEST: VbglGRPerform - rc=%Rrc!\n", rc
));
2007 Log(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed; VMMDev rc=%Rrc!\n", pReqCopy
->rc
));
2011 VbglGRFree(pReqCopy
);
2016 #ifdef VBOX_WITH_HGCM
2018 AssertCompile(RT_INDEFINITE_WAIT
== (uint32_t)RT_INDEFINITE_WAIT
); /* assumed by code below */
2020 /** Worker for vgdrvHgcmAsyncWaitCallback*. */
2021 static int vgdrvHgcmAsyncWaitCallbackWorker(VMMDevHGCMRequestHeader
volatile *pHdr
, PVBOXGUESTDEVEXT pDevExt
,
2022 bool fInterruptible
, uint32_t cMillies
)
2027 * Check to see if the condition was met by the time we got here.
2029 * We create a simple poll loop here for dealing with out-of-memory
2030 * conditions since the caller isn't necessarily able to deal with
2031 * us returning too early.
2033 PVBOXGUESTWAIT pWait
;
2036 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
2037 if ((pHdr
->fu32Flags
& VBOX_HGCM_REQ_DONE
) != 0)
2039 RTSpinlockRelease(pDevExt
->EventSpinlock
);
2040 return VINF_SUCCESS
;
2042 RTSpinlockRelease(pDevExt
->EventSpinlock
);
2044 pWait
= vgdrvWaitAlloc(pDevExt
, NULL
);
2048 return VERR_INTERRUPTED
;
2051 pWait
->fReqEvents
= VMMDEV_EVENT_HGCM
;
2052 pWait
->pHGCMReq
= pHdr
;
2055 * Re-enter the spinlock and re-check for the condition.
2056 * If the condition is met, return.
2057 * Otherwise link us into the HGCM wait list and go to sleep.
2059 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
2060 RTListAppend(&pDevExt
->HGCMWaitList
, &pWait
->ListNode
);
2061 if ((pHdr
->fu32Flags
& VBOX_HGCM_REQ_DONE
) != 0)
2063 vgdrvWaitFreeLocked(pDevExt
, pWait
);
2064 RTSpinlockRelease(pDevExt
->EventSpinlock
);
2065 return VINF_SUCCESS
;
2067 RTSpinlockRelease(pDevExt
->EventSpinlock
);
2070 rc
= RTSemEventMultiWaitNoResume(pWait
->Event
, cMillies
);
2072 rc
= RTSemEventMultiWait(pWait
->Event
, cMillies
);
2073 if (rc
== VERR_SEM_DESTROYED
)
2077 * Unlink, free and return.
2080 && rc
!= VERR_TIMEOUT
2081 && ( !fInterruptible
2082 || rc
!= VERR_INTERRUPTED
))
2083 LogRel(("vgdrvHgcmAsyncWaitCallback: wait failed! %Rrc\n", rc
));
2085 vgdrvWaitFreeUnlocked(pDevExt
, pWait
);
2091 * This is a callback for dealing with async waits.
2093 * It operates in a manner similar to vgdrvIoCtl_WaitEvent.
2095 static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallback(VMMDevHGCMRequestHeader
*pHdr
, void *pvUser
, uint32_t u32User
)
2097 PVBOXGUESTDEVEXT pDevExt
= (PVBOXGUESTDEVEXT
)pvUser
;
2098 LogFlow(("vgdrvHgcmAsyncWaitCallback: requestType=%d\n", pHdr
->header
.requestType
));
2099 return vgdrvHgcmAsyncWaitCallbackWorker((VMMDevHGCMRequestHeader
volatile *)pHdr
, pDevExt
,
2100 false /* fInterruptible */, u32User
/* cMillies */);
2105 * This is a callback for dealing with async waits with a timeout.
2107 * It operates in a manner similar to vgdrvIoCtl_WaitEvent.
2109 static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallbackInterruptible(VMMDevHGCMRequestHeader
*pHdr
, void *pvUser
, uint32_t u32User
)
2111 PVBOXGUESTDEVEXT pDevExt
= (PVBOXGUESTDEVEXT
)pvUser
;
2112 LogFlow(("vgdrvHgcmAsyncWaitCallbackInterruptible: requestType=%d\n", pHdr
->header
.requestType
));
2113 return vgdrvHgcmAsyncWaitCallbackWorker((VMMDevHGCMRequestHeader
volatile *)pHdr
, pDevExt
,
2114 true /* fInterruptible */, u32User
/* cMillies */);
2118 static int vgdrvIoCtl_HGCMConnect(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
2119 VBoxGuestHGCMConnectInfo
*pInfo
, size_t *pcbDataReturned
)
2124 * The VbglHGCMConnect call will invoke the callback if the HGCM
2125 * call is performed in an ASYNC fashion. The function is not able
2126 * to deal with cancelled requests.
2128 Log(("VBOXGUEST_IOCTL_HGCM_CONNECT: %.128s\n",
2129 pInfo
->Loc
.type
== VMMDevHGCMLoc_LocalHost
|| pInfo
->Loc
.type
== VMMDevHGCMLoc_LocalHost_Existing
2130 ? pInfo
->Loc
.u
.host
.achName
: "<not local host>"));
2132 rc
= VbglR0HGCMInternalConnect(pInfo
, vgdrvHgcmAsyncWaitCallback
, pDevExt
, RT_INDEFINITE_WAIT
);
2135 Log(("VBOXGUEST_IOCTL_HGCM_CONNECT: u32Client=%RX32 result=%Rrc (rc=%Rrc)\n",
2136 pInfo
->u32ClientID
, pInfo
->result
, rc
));
2137 if (RT_SUCCESS(pInfo
->result
))
2140 * Append the client id to the client id table.
2141 * If the table has somehow become filled up, we'll disconnect the session.
2144 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
2145 for (i
= 0; i
< RT_ELEMENTS(pSession
->aHGCMClientIds
); i
++)
2146 if (!pSession
->aHGCMClientIds
[i
])
2148 pSession
->aHGCMClientIds
[i
] = pInfo
->u32ClientID
;
2151 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
2152 if (i
>= RT_ELEMENTS(pSession
->aHGCMClientIds
))
2154 VBoxGuestHGCMDisconnectInfo Info
;
2155 LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CONNECT: too many HGCMConnect calls for one session!\n"));
2157 Info
.u32ClientID
= pInfo
->u32ClientID
;
2158 VbglR0HGCMInternalDisconnect(&Info
, vgdrvHgcmAsyncWaitCallback
, pDevExt
, RT_INDEFINITE_WAIT
);
2159 return VERR_TOO_MANY_OPEN_FILES
;
2164 if (pcbDataReturned
)
2165 *pcbDataReturned
= sizeof(*pInfo
);
2171 static int vgdrvIoCtl_HGCMDisconnect(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
2172 VBoxGuestHGCMDisconnectInfo
*pInfo
, size_t *pcbDataReturned
)
2175 * Validate the client id and invalidate its entry while we're in the call.
2178 const uint32_t u32ClientId
= pInfo
->u32ClientID
;
2180 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
2181 for (i
= 0; i
< RT_ELEMENTS(pSession
->aHGCMClientIds
); i
++)
2182 if (pSession
->aHGCMClientIds
[i
] == u32ClientId
)
2184 pSession
->aHGCMClientIds
[i
] = UINT32_MAX
;
2187 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
2188 if (i
>= RT_ELEMENTS(pSession
->aHGCMClientIds
))
2190 LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_DISCONNECT: u32Client=%RX32\n", u32ClientId
));
2191 return VERR_INVALID_HANDLE
;
2195 * The VbglHGCMConnect call will invoke the callback if the HGCM
2196 * call is performed in an ASYNC fashion. The function is not able
2197 * to deal with cancelled requests.
2199 Log(("VBOXGUEST_IOCTL_HGCM_DISCONNECT: u32Client=%RX32\n", pInfo
->u32ClientID
));
2200 rc
= VbglR0HGCMInternalDisconnect(pInfo
, vgdrvHgcmAsyncWaitCallback
, pDevExt
, RT_INDEFINITE_WAIT
);
2203 LogFlow(("VBOXGUEST_IOCTL_HGCM_DISCONNECT: result=%Rrc\n", pInfo
->result
));
2204 if (pcbDataReturned
)
2205 *pcbDataReturned
= sizeof(*pInfo
);
2208 /* Update the client id array according to the result. */
2209 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
2210 if (pSession
->aHGCMClientIds
[i
] == UINT32_MAX
)
2211 pSession
->aHGCMClientIds
[i
] = RT_SUCCESS(rc
) && RT_SUCCESS(pInfo
->result
) ? 0 : u32ClientId
;
2212 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
2218 static int vgdrvIoCtl_HGCMCall(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, VBoxGuestHGCMCallInfo
*pInfo
,
2219 uint32_t cMillies
, bool fInterruptible
, bool f32bit
, bool fUserData
,
2220 size_t cbExtra
, size_t cbData
, size_t *pcbDataReturned
)
2222 const uint32_t u32ClientId
= pInfo
->u32ClientID
;
2229 * Some more validations.
2231 if (pInfo
->cParms
> 4096) /* (Just make sure it doesn't overflow the next check.) */
2233 LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cParm=%RX32 is not sane\n", pInfo
->cParms
));
2234 return VERR_INVALID_PARAMETER
;
2237 cbActual
= cbExtra
+ sizeof(*pInfo
);
2238 #ifdef RT_ARCH_AMD64
2240 cbActual
+= pInfo
->cParms
* sizeof(HGCMFunctionParameter32
);
2243 cbActual
+= pInfo
->cParms
* sizeof(HGCMFunctionParameter
);
2244 if (cbData
< cbActual
)
2246 LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cbData=%#zx (%zu) required size is %#zx (%zu)\n",
2247 cbData
, cbData
, cbActual
, cbActual
));
2248 return VERR_INVALID_PARAMETER
;
2252 * Validate the client id.
2254 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
2255 for (i
= 0; i
< RT_ELEMENTS(pSession
->aHGCMClientIds
); i
++)
2256 if (pSession
->aHGCMClientIds
[i
] == u32ClientId
)
2258 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
2259 if (RT_UNLIKELY(i
>= RT_ELEMENTS(pSession
->aHGCMClientIds
)))
2261 LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CALL: Invalid handle. u32Client=%RX32\n", u32ClientId
));
2262 return VERR_INVALID_HANDLE
;
2266 * The VbglHGCMCall call will invoke the callback if the HGCM
2267 * call is performed in an ASYNC fashion. This function can
2268 * deal with cancelled requests, so we let user more requests
2269 * be interruptible (should add a flag for this later I guess).
2271 LogFlow(("VBOXGUEST_IOCTL_HGCM_CALL: u32Client=%RX32\n", pInfo
->u32ClientID
));
2272 fFlags
= !fUserData
&& pSession
->R0Process
== NIL_RTR0PROCESS
? VBGLR0_HGCMCALL_F_KERNEL
: VBGLR0_HGCMCALL_F_USER
;
2273 uint32_t cbInfo
= (uint32_t)(cbData
- cbExtra
);
2274 #ifdef RT_ARCH_AMD64
2278 rc
= VbglR0HGCMInternalCall32(pInfo
, cbInfo
, fFlags
, vgdrvHgcmAsyncWaitCallbackInterruptible
, pDevExt
, cMillies
);
2280 rc
= VbglR0HGCMInternalCall32(pInfo
, cbInfo
, fFlags
, vgdrvHgcmAsyncWaitCallback
, pDevExt
, cMillies
);
2286 rc
= VbglR0HGCMInternalCall(pInfo
, cbInfo
, fFlags
, vgdrvHgcmAsyncWaitCallbackInterruptible
, pDevExt
, cMillies
);
2288 rc
= VbglR0HGCMInternalCall(pInfo
, cbInfo
, fFlags
, vgdrvHgcmAsyncWaitCallback
, pDevExt
, cMillies
);
2292 LogFlow(("VBOXGUEST_IOCTL_HGCM_CALL: result=%Rrc\n", pInfo
->result
));
2293 if (pcbDataReturned
)
2294 *pcbDataReturned
= cbActual
;
2298 if ( rc
!= VERR_INTERRUPTED
2299 && rc
!= VERR_TIMEOUT
)
2300 LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CALL: %s Failed. rc=%Rrc.\n", f32bit
? "32" : "64", rc
));
2302 Log(("VBOXGUEST_IOCTL_HGCM_CALL: %s Failed. rc=%Rrc.\n", f32bit
? "32" : "64", rc
));
2307 #endif /* VBOX_WITH_HGCM */
2310 * Handle VBOXGUEST_IOCTL_CHECK_BALLOON from R3.
2312 * Ask the host for the size of the balloon and try to set it accordingly. If
2313 * this approach fails because it's not supported, return with fHandleInR3 set
2314 * and let the user land supply memory we can lock via the other ioctl.
2316 * @returns VBox status code.
2318 * @param pDevExt The device extension.
2319 * @param pSession The session.
2320 * @param pInfo The output buffer.
2321 * @param pcbDataReturned Where to store the amount of returned data. Can
2324 static int vgdrvIoCtl_CheckMemoryBalloon(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
2325 VBoxGuestCheckBalloonInfo
*pInfo
, size_t *pcbDataReturned
)
2327 VMMDevGetMemBalloonChangeRequest
*pReq
;
2330 LogFlow(("VBOXGUEST_IOCTL_CHECK_BALLOON:\n"));
2331 rc
= RTSemFastMutexRequest(pDevExt
->MemBalloon
.hMtx
);
2332 AssertRCReturn(rc
, rc
);
2335 * The first user trying to query/change the balloon becomes the
2336 * owner and owns it until the session is closed (vgdrvCloseMemBalloon).
2338 if ( pDevExt
->MemBalloon
.pOwner
!= pSession
2339 && pDevExt
->MemBalloon
.pOwner
== NULL
)
2340 pDevExt
->MemBalloon
.pOwner
= pSession
;
2342 if (pDevExt
->MemBalloon
.pOwner
== pSession
)
2344 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(VMMDevGetMemBalloonChangeRequest
), VMMDevReq_GetMemBalloonChangeRequest
);
2348 * This is a response to that event. Setting this bit means that
2349 * we request the value from the host and change the guest memory
2350 * balloon according to this value.
2352 pReq
->eventAck
= VMMDEV_EVENT_BALLOON_CHANGE_REQUEST
;
2353 rc
= VbglGRPerform(&pReq
->header
);
2356 Assert(pDevExt
->MemBalloon
.cMaxChunks
== pReq
->cPhysMemChunks
|| pDevExt
->MemBalloon
.cMaxChunks
== 0);
2357 pDevExt
->MemBalloon
.cMaxChunks
= pReq
->cPhysMemChunks
;
2359 pInfo
->cBalloonChunks
= pReq
->cBalloonChunks
;
2360 pInfo
->fHandleInR3
= false;
2362 rc
= vgdrvSetBalloonSizeKernel(pDevExt
, pReq
->cBalloonChunks
, &pInfo
->fHandleInR3
);
2363 /* Ignore various out of memory failures. */
2364 if ( rc
== VERR_NO_MEMORY
2365 || rc
== VERR_NO_PHYS_MEMORY
2366 || rc
== VERR_NO_CONT_MEMORY
)
2369 if (pcbDataReturned
)
2370 *pcbDataReturned
= sizeof(VBoxGuestCheckBalloonInfo
);
2373 LogRel(("VBOXGUEST_IOCTL_CHECK_BALLOON: VbglGRPerform failed. rc=%Rrc\n", rc
));
2374 VbglGRFree(&pReq
->header
);
2378 rc
= VERR_PERMISSION_DENIED
;
2380 RTSemFastMutexRelease(pDevExt
->MemBalloon
.hMtx
);
2381 LogFlow(("VBOXGUEST_IOCTL_CHECK_BALLOON returns %Rrc\n", rc
));
2387 * Handle a request for changing the memory balloon.
2389 * @returns VBox status code.
2391 * @param pDevExt The device extention.
2392 * @param pSession The session.
2393 * @param pInfo The change request structure (input).
2394 * @param pcbDataReturned Where to store the amount of returned data. Can
2397 static int vgdrvIoCtl_ChangeMemoryBalloon(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
2398 VBoxGuestChangeBalloonInfo
*pInfo
, size_t *pcbDataReturned
)
2401 LogFlow(("VBOXGUEST_IOCTL_CHANGE_BALLOON: fInflate=%RTbool u64ChunkAddr=%#RX64\n", pInfo
->fInflate
, pInfo
->u64ChunkAddr
));
2403 rc
= RTSemFastMutexRequest(pDevExt
->MemBalloon
.hMtx
);
2404 AssertRCReturn(rc
, rc
);
2406 if (!pDevExt
->MemBalloon
.fUseKernelAPI
)
2409 * The first user trying to query/change the balloon becomes the
2410 * owner and owns it until the session is closed (vgdrvCloseMemBalloon).
2412 if ( pDevExt
->MemBalloon
.pOwner
!= pSession
2413 && pDevExt
->MemBalloon
.pOwner
== NULL
)
2414 pDevExt
->MemBalloon
.pOwner
= pSession
;
2416 if (pDevExt
->MemBalloon
.pOwner
== pSession
)
2418 rc
= vgdrvSetBalloonSizeFromUser(pDevExt
, pSession
, pInfo
->u64ChunkAddr
, !!pInfo
->fInflate
);
2419 if (pcbDataReturned
)
2420 *pcbDataReturned
= 0;
2423 rc
= VERR_PERMISSION_DENIED
;
2426 rc
= VERR_PERMISSION_DENIED
;
2428 RTSemFastMutexRelease(pDevExt
->MemBalloon
.hMtx
);
2434 * Handle a request for writing a core dump of the guest on the host.
2436 * @returns VBox status code.
2438 * @param pDevExt The device extension.
2439 * @param pInfo The output buffer.
2441 static int vgdrvIoCtl_WriteCoreDump(PVBOXGUESTDEVEXT pDevExt
, VBoxGuestWriteCoreDump
*pInfo
)
2443 VMMDevReqWriteCoreDump
*pReq
= NULL
;
2445 LogFlow(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP\n"));
2448 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_WriteCoreDump
);
2451 pReq
->fFlags
= pInfo
->fFlags
;
2452 rc
= VbglGRPerform(&pReq
->header
);
2454 Log(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP: VbglGRPerform failed, rc=%Rrc!\n", rc
));
2456 VbglGRFree(&pReq
->header
);
2459 Log(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
2460 sizeof(*pReq
), sizeof(*pReq
), rc
));
2466 * Guest backdoor logging.
2468 * @returns VBox status code.
2470 * @param pDevExt The device extension.
2471 * @param pch The log message (need not be NULL terminated).
2472 * @param cbData Size of the buffer.
2473 * @param pcbDataReturned Where to store the amount of returned data. Can be NULL.
2474 * @param fUserSession Copy of VBOXGUESTSESSION::fUserSession for the
2475 * call. True normal user, false root user.
2477 static int vgdrvIoCtl_Log(PVBOXGUESTDEVEXT pDevExt
, const char *pch
, size_t cbData
, size_t *pcbDataReturned
, bool fUserSession
)
2479 if (pDevExt
->fLoggingEnabled
)
2480 RTLogBackdoorPrintf("%.*s", cbData
, pch
);
2481 else if (!fUserSession
)
2482 LogRel(("%.*s", cbData
, pch
));
2484 Log(("%.*s", cbData
, pch
));
2485 if (pcbDataReturned
)
2486 *pcbDataReturned
= 0;
2487 return VINF_SUCCESS
;
2491 /** @name Guest Capabilities, Mouse Status and Event Filter
2496 * Clears a bit usage tracker (init time).
2498 * @param pTracker The tracker to clear.
2500 static void vgdrvBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker
)
2503 AssertCompile(sizeof(pTracker
->acPerBitUsage
) == 32 * sizeof(uint32_t));
2505 for (iBit
= 0; iBit
< 32; iBit
++)
2506 pTracker
->acPerBitUsage
[iBit
] = 0;
2507 pTracker
->fMask
= 0;
2513 * Checks that pTracker->fMask is correct and that the usage values are within
2516 * @param pTracker The tracker.
2517 * @param cMax Max valid usage value.
2518 * @param pszWhat Identifies the tracker in assertions.
2520 static void vgdrvBitUsageTrackerCheckMask(PCVBOXGUESTBITUSAGETRACER pTracker
, uint32_t cMax
, const char *pszWhat
)
2524 AssertCompile(sizeof(pTracker
->acPerBitUsage
) == 32 * sizeof(uint32_t));
2526 for (iBit
= 0; iBit
< 32; iBit
++)
2527 if (pTracker
->acPerBitUsage
[iBit
])
2529 fMask
|= RT_BIT_32(iBit
);
2530 AssertMsg(pTracker
->acPerBitUsage
[iBit
] <= cMax
,
2531 ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat
, iBit
, pTracker
->acPerBitUsage
[iBit
], cMax
));
2534 AssertMsg(fMask
== pTracker
->fMask
, ("%s: %#x vs %#x\n", pszWhat
, fMask
, pTracker
->fMask
));
2540 * Applies a change to the bit usage tracker.
2543 * @returns true if the mask changed, false if not.
2544 * @param pTracker The bit usage tracker.
2545 * @param fChanged The bits to change.
2546 * @param fPrevious The previous value of the bits.
2547 * @param cMax The max valid usage value for assertions.
2548 * @param pszWhat Identifies the tracker in assertions.
2550 static bool vgdrvBitUsageTrackerChange(PVBOXGUESTBITUSAGETRACER pTracker
, uint32_t fChanged
, uint32_t fPrevious
,
2551 uint32_t cMax
, const char *pszWhat
)
2553 bool fGlobalChange
= false;
2554 AssertCompile(sizeof(pTracker
->acPerBitUsage
) == 32 * sizeof(uint32_t));
2558 uint32_t const iBit
= ASMBitFirstSetU32(fChanged
) - 1;
2559 uint32_t const fBitMask
= RT_BIT_32(iBit
);
2560 Assert(iBit
< 32); Assert(fBitMask
& fChanged
);
2562 if (fBitMask
& fPrevious
)
2564 pTracker
->acPerBitUsage
[iBit
] -= 1;
2565 AssertMsg(pTracker
->acPerBitUsage
[iBit
] <= cMax
,
2566 ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat
, iBit
, pTracker
->acPerBitUsage
[iBit
], cMax
));
2567 if (pTracker
->acPerBitUsage
[iBit
] == 0)
2569 fGlobalChange
= true;
2570 pTracker
->fMask
&= ~fBitMask
;
2575 pTracker
->acPerBitUsage
[iBit
] += 1;
2576 AssertMsg(pTracker
->acPerBitUsage
[iBit
] > 0 && pTracker
->acPerBitUsage
[iBit
] <= cMax
,
2577 ("pTracker->acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat
, iBit
, pTracker
->acPerBitUsage
[iBit
], cMax
));
2578 if (pTracker
->acPerBitUsage
[iBit
] == 1)
2580 fGlobalChange
= true;
2581 pTracker
->fMask
|= fBitMask
;
2585 fChanged
&= ~fBitMask
;
2589 vgdrvBitUsageTrackerCheckMask(pTracker
, cMax
, pszWhat
);
2591 NOREF(pszWhat
); NOREF(cMax
);
2592 return fGlobalChange
;
2597 * Init and termination worker for resetting the (host) event filter on the host
2599 * @returns VBox status code.
2600 * @param pDevExt The device extension.
2601 * @param fFixedEvents Fixed events (init time).
2603 static int vgdrvResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt
, uint32_t fFixedEvents
)
2605 VMMDevCtlGuestFilterMask
*pReq
;
2606 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_CtlGuestFilterMask
);
2609 pReq
->u32NotMask
= UINT32_MAX
& ~fFixedEvents
;
2610 pReq
->u32OrMask
= fFixedEvents
;
2611 rc
= VbglGRPerform(&pReq
->header
);
2613 LogRelFunc(("failed with rc=%Rrc\n", rc
));
2614 VbglGRFree(&pReq
->header
);
2622 * Changes the event filter mask for the given session.
2624 * This is called in response to VBOXGUEST_IOCTL_CTL_FILTER_MASK as well as to
2625 * do session cleanup.
2627 * @returns VBox status code.
2628 * @param pDevExt The device extension.
2629 * @param pSession The session.
2630 * @param fOrMask The events to add.
2631 * @param fNotMask The events to remove.
2632 * @param fSessionTermination Set if we're called by the session cleanup code.
2633 * This tweaks the error handling so we perform
2634 * proper session cleanup even if the host
2637 * @remarks Takes the session spinlock.
2639 static int vgdrvSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
2640 uint32_t fOrMask
, uint32_t fNotMask
, bool fSessionTermination
)
2642 VMMDevCtlGuestFilterMask
*pReq
;
2648 * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
2650 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_CtlGuestFilterMask
);
2653 else if (!fSessionTermination
)
2655 LogRel(("vgdrvSetSessionFilterMask: VbglGRAlloc failure: %Rrc\n", rc
));
2659 pReq
= NULL
; /* Ignore failure, we must do session cleanup. */
2662 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
2665 * Apply the changes to the session mask.
2667 fPrevious
= pSession
->fEventFilter
;
2668 pSession
->fEventFilter
|= fOrMask
;
2669 pSession
->fEventFilter
&= ~fNotMask
;
2672 * If anything actually changed, update the global usage counters.
2674 fChanged
= fPrevious
^ pSession
->fEventFilter
;
2677 bool fGlobalChange
= vgdrvBitUsageTrackerChange(&pDevExt
->EventFilterTracker
, fChanged
, fPrevious
,
2678 pDevExt
->cSessions
, "EventFilterTracker");
2681 * If there are global changes, update the event filter on the host.
2683 if (fGlobalChange
|| pDevExt
->fEventFilterHost
== UINT32_MAX
)
2685 Assert(pReq
|| fSessionTermination
);
2688 pReq
->u32OrMask
= pDevExt
->fFixedEvents
| pDevExt
->EventFilterTracker
.fMask
;
2689 if (pReq
->u32OrMask
== pDevExt
->fEventFilterHost
)
2693 pDevExt
->fEventFilterHost
= pReq
->u32OrMask
;
2694 pReq
->u32NotMask
= ~pReq
->u32OrMask
;
2695 rc
= VbglGRPerform(&pReq
->header
);
2699 * Failed, roll back (unless it's session termination time).
2701 pDevExt
->fEventFilterHost
= UINT32_MAX
;
2702 if (!fSessionTermination
)
2704 vgdrvBitUsageTrackerChange(&pDevExt
->EventFilterTracker
, fChanged
, pSession
->fEventFilter
,
2705 pDevExt
->cSessions
, "EventFilterTracker");
2706 pSession
->fEventFilter
= fPrevious
;
2716 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
2718 VbglGRFree(&pReq
->header
);
2724 * Handle VBOXGUEST_IOCTL_CTL_FILTER_MASK.
2726 * @returns VBox status code.
2728 * @param pDevExt The device extension.
2729 * @param pSession The session.
2730 * @param pInfo The request.
2732 static int vgdrvIoCtl_CtlFilterMask(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, VBoxGuestFilterMaskInfo
*pInfo
)
2734 LogFlow(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: or=%#x not=%#x\n", pInfo
->u32OrMask
, pInfo
->u32NotMask
));
2736 if ((pInfo
->u32OrMask
| pInfo
->u32NotMask
) & ~VMMDEV_EVENT_VALID_EVENT_MASK
)
2738 Log(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: or=%#x not=%#x: Invalid masks!\n", pInfo
->u32OrMask
, pInfo
->u32NotMask
));
2739 return VERR_INVALID_PARAMETER
;
2742 return vgdrvSetSessionEventFilter(pDevExt
, pSession
, pInfo
->u32OrMask
, pInfo
->u32NotMask
, false /*fSessionTermination*/);
2747 * Init and termination worker for set mouse feature status to zero on the host.
2749 * @returns VBox status code.
2750 * @param pDevExt The device extension.
2752 static int vgdrvResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt
)
2754 VMMDevReqMouseStatus
*pReq
;
2755 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_SetMouseStatus
);
2758 pReq
->mouseFeatures
= 0;
2759 pReq
->pointerXPos
= 0;
2760 pReq
->pointerYPos
= 0;
2761 rc
= VbglGRPerform(&pReq
->header
);
2763 LogRelFunc(("failed with rc=%Rrc\n", rc
));
2764 VbglGRFree(&pReq
->header
);
2772 * Changes the mouse status mask for the given session.
2774 * This is called in response to VBOXGUEST_IOCTL_SET_MOUSE_STATUS as well as to
2775 * do session cleanup.
2777 * @returns VBox status code.
2778 * @param pDevExt The device extension.
2779 * @param pSession The session.
2780 * @param fOrMask The status flags to add.
2781 * @param fNotMask The status flags to remove.
2782 * @param fSessionTermination Set if we're called by the session cleanup code.
2783 * This tweaks the error handling so we perform
2784 * proper session cleanup even if the host
2787 * @remarks Takes the session spinlock.
2789 static int vgdrvSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
2790 uint32_t fOrMask
, uint32_t fNotMask
, bool fSessionTermination
)
2792 VMMDevReqMouseStatus
*pReq
;
2798 * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
2800 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_SetMouseStatus
);
2803 else if (!fSessionTermination
)
2805 LogRel(("vgdrvSetSessionMouseStatus: VbglGRAlloc failure: %Rrc\n", rc
));
2809 pReq
= NULL
; /* Ignore failure, we must do session cleanup. */
2812 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
2815 * Apply the changes to the session mask.
2817 fPrevious
= pSession
->fMouseStatus
;
2818 pSession
->fMouseStatus
|= fOrMask
;
2819 pSession
->fMouseStatus
&= ~fNotMask
;
2822 * If anything actually changed, update the global usage counters.
2824 fChanged
= fPrevious
^ pSession
->fMouseStatus
;
2827 bool fGlobalChange
= vgdrvBitUsageTrackerChange(&pDevExt
->MouseStatusTracker
, fChanged
, fPrevious
,
2828 pDevExt
->cSessions
, "MouseStatusTracker");
2831 * If there are global changes, update the event filter on the host.
2833 if (fGlobalChange
|| pDevExt
->fMouseStatusHost
== UINT32_MAX
)
2835 Assert(pReq
|| fSessionTermination
);
2838 pReq
->mouseFeatures
= pDevExt
->MouseStatusTracker
.fMask
;
2839 if (pReq
->mouseFeatures
== pDevExt
->fMouseStatusHost
)
2843 pDevExt
->fMouseStatusHost
= pReq
->mouseFeatures
;
2844 pReq
->pointerXPos
= 0;
2845 pReq
->pointerYPos
= 0;
2846 rc
= VbglGRPerform(&pReq
->header
);
2850 * Failed, roll back (unless it's session termination time).
2852 pDevExt
->fMouseStatusHost
= UINT32_MAX
;
2853 if (!fSessionTermination
)
2855 vgdrvBitUsageTrackerChange(&pDevExt
->MouseStatusTracker
, fChanged
, pSession
->fMouseStatus
,
2856 pDevExt
->cSessions
, "MouseStatusTracker");
2857 pSession
->fMouseStatus
= fPrevious
;
2867 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
2869 VbglGRFree(&pReq
->header
);
2875 * Sets the mouse status features for this session and updates them globally.
2877 * @returns VBox status code.
2879 * @param pDevExt The device extention.
2880 * @param pSession The session.
2881 * @param fFeatures New bitmap of enabled features.
2883 static int vgdrvIoCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, uint32_t fFeatures
)
2885 LogFlow(("VBOXGUEST_IOCTL_SET_MOUSE_STATUS: features=%#x\n", fFeatures
));
2887 if (fFeatures
& ~VMMDEV_MOUSE_GUEST_MASK
)
2888 return VERR_INVALID_PARAMETER
;
2890 return vgdrvSetSessionMouseStatus(pDevExt
, pSession
, fFeatures
, ~fFeatures
, false /*fSessionTermination*/);
2895 * Return the mask of VMM device events that this session is allowed to see (wrt
2896 * to "acquire" mode guest capabilities).
2898 * The events associated with guest capabilities in "acquire" mode will be
2899 * restricted to sessions which has acquired the respective capabilities.
2900 * If someone else tries to wait for acquired events, they won't be woken up
2901 * when the event becomes pending. Should some other thread in the session
2902 * acquire the capability while the corresponding event is pending, the waiting
2903 * thread will woken up.
2905 * @returns Mask of events valid for the given session.
2906 * @param pDevExt The device extension.
2907 * @param pSession The session.
2909 * @remarks Needs only be called when dispatching events in the
2910 * VBOXGUEST_ACQUIRE_STYLE_EVENTS mask.
2912 static uint32_t vgdrvGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
)
2914 uint32_t fAcquireModeGuestCaps
;
2915 uint32_t fAcquiredGuestCaps
;
2916 uint32_t fAllowedEvents
;
2919 * Note! Reads pSession->fAcquiredGuestCaps and pDevExt->fAcquireModeGuestCaps
2920 * WITHOUT holding VBOXGUESTDEVEXT::SessionSpinlock.
2922 fAcquireModeGuestCaps
= ASMAtomicUoReadU32(&pDevExt
->fAcquireModeGuestCaps
);
2923 if (fAcquireModeGuestCaps
== 0)
2924 return VMMDEV_EVENT_VALID_EVENT_MASK
;
2925 fAcquiredGuestCaps
= ASMAtomicUoReadU32(&pSession
->fAcquiredGuestCaps
);
2928 * Calculate which events to allow according to the cap config and caps
2929 * acquired by the session.
2931 fAllowedEvents
= VMMDEV_EVENT_VALID_EVENT_MASK
;
2932 if ( !(fAcquiredGuestCaps
& VMMDEV_GUEST_SUPPORTS_GRAPHICS
)
2933 && (fAcquireModeGuestCaps
& VMMDEV_GUEST_SUPPORTS_GRAPHICS
))
2934 fAllowedEvents
&= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
;
2936 if ( !(fAcquiredGuestCaps
& VMMDEV_GUEST_SUPPORTS_SEAMLESS
)
2937 && (fAcquireModeGuestCaps
& VMMDEV_GUEST_SUPPORTS_SEAMLESS
))
2938 fAllowedEvents
&= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST
;
2940 return fAllowedEvents
;
2945 * Init and termination worker for set guest capabilities to zero on the host.
2947 * @returns VBox status code.
2948 * @param pDevExt The device extension.
2950 static int vgdrvResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt
)
2952 VMMDevReqGuestCapabilities2
*pReq
;
2953 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_SetGuestCapabilities
);
2956 pReq
->u32NotMask
= UINT32_MAX
;
2957 pReq
->u32OrMask
= 0;
2958 rc
= VbglGRPerform(&pReq
->header
);
2961 LogRelFunc(("failed with rc=%Rrc\n", rc
));
2962 VbglGRFree(&pReq
->header
);
2970 * Sets the guest capabilities to the host while holding the lock.
2972 * This will ASSUME that we're the ones in charge of the mask, so
2973 * we'll simply clear all bits we don't set.
2975 * @returns VBox status code.
2976 * @param pDevExt The device extension.
2977 * @param pReq The request.
2979 static int vgdrvUpdateCapabilitiesOnHostWithReqAndLock(PVBOXGUESTDEVEXT pDevExt
, VMMDevReqGuestCapabilities2
*pReq
)
2983 pReq
->u32OrMask
= pDevExt
->fAcquiredGuestCaps
| pDevExt
->SetGuestCapsTracker
.fMask
;
2984 if (pReq
->u32OrMask
== pDevExt
->fGuestCapsHost
)
2988 pDevExt
->fGuestCapsHost
= pReq
->u32OrMask
;
2989 pReq
->u32NotMask
= ~pReq
->u32OrMask
;
2990 rc
= VbglGRPerform(&pReq
->header
);
2992 pDevExt
->fGuestCapsHost
= UINT32_MAX
;
3000 * Switch a set of capabilities into "acquire" mode and (maybe) acquire them for
3001 * the given session.
3003 * This is called in response to VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE as well as
3004 * to do session cleanup.
3006 * @returns VBox status code.
3007 * @param pDevExt The device extension.
3008 * @param pSession The session.
3009 * @param fOrMask The capabilities to add .
3010 * @param fNotMask The capabilities to remove. Ignored in
3011 * VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE.
3012 * @param enmFlags Confusing operation modifier.
3013 * VBOXGUESTCAPSACQUIRE_FLAGS_NONE means to both
3014 * configure and acquire/release the capabilities.
3015 * VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
3016 * means only configure capabilities in the
3017 * @a fOrMask capabilities for "acquire" mode.
3018 * @param fSessionTermination Set if we're called by the session cleanup code.
3019 * This tweaks the error handling so we perform
3020 * proper session cleanup even if the host
3023 * @remarks Takes both the session and event spinlocks.
3025 static int vgdrvAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
3026 uint32_t fOrMask
, uint32_t fNotMask
, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags
,
3027 bool fSessionTermination
)
3029 uint32_t fCurrentOwnedCaps
;
3030 uint32_t fSessionRemovedCaps
;
3031 uint32_t fSessionAddedCaps
;
3032 uint32_t fOtherConflictingCaps
;
3033 VMMDevReqGuestCapabilities2
*pReq
= NULL
;
3038 * Validate and adjust input.
3040 if (fOrMask
& ~( VMMDEV_GUEST_SUPPORTS_SEAMLESS
3041 | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING
3042 | VMMDEV_GUEST_SUPPORTS_GRAPHICS
) )
3044 LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x -- invalid fOrMask\n",
3045 pSession
, fOrMask
, fNotMask
, enmFlags
));
3046 return VERR_INVALID_PARAMETER
;
3049 if ( enmFlags
!= VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
3050 && enmFlags
!= VBOXGUESTCAPSACQUIRE_FLAGS_NONE
)
3052 LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: invalid enmFlags %d\n",
3053 pSession
, fOrMask
, fNotMask
, enmFlags
));
3054 return VERR_INVALID_PARAMETER
;
3056 Assert(!fOrMask
|| !fSessionTermination
);
3058 /* The fNotMask no need to have all values valid, invalid ones will simply be ignored. */
3059 fNotMask
&= ~fOrMask
;
3062 * Preallocate a update request if we're about to do more than just configure
3063 * the capability mode.
3065 if (enmFlags
!= VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
)
3067 rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_SetGuestCapabilities
);
3069 { /* do nothing */ }
3070 else if (!fSessionTermination
)
3072 LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: VbglGRAlloc failure: %Rrc\n",
3073 pSession
, fOrMask
, fNotMask
, enmFlags
, rc
));
3077 pReq
= NULL
; /* Ignore failure, we must do session cleanup. */
3081 * Try switch the capabilities in the OR mask into "acquire" mode.
3083 * Note! We currently ignore anyone which may already have "set" the capabilities
3084 * in fOrMask. Perhaps not the best way to handle it, but it's simple...
3086 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
3088 if (!(pDevExt
->fSetModeGuestCaps
& fOrMask
))
3089 pDevExt
->fAcquireModeGuestCaps
|= fOrMask
;
3092 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3095 VbglGRFree(&pReq
->header
);
3096 AssertMsgFailed(("Trying to change caps mode: %#x\n", fOrMask
));
3097 LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: calling caps acquire for set caps\n",
3098 pSession
, fOrMask
, fNotMask
, enmFlags
));
3099 return VERR_INVALID_STATE
;
3103 * If we only wanted to switch the capabilities into "acquire" mode, we're done now.
3105 if (enmFlags
& VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
)
3107 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3110 Log(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: configured acquire caps: 0x%x\n",
3111 pSession
, fOrMask
, fNotMask
, enmFlags
));
3112 return VINF_SUCCESS
;
3114 Assert(pReq
|| fSessionTermination
);
3117 * Caller wants to acquire/release the capabilities too.
3119 * Note! The mode change of the capabilities above won't be reverted on
3120 * failure, this is intentional.
3122 fCurrentOwnedCaps
= pSession
->fAcquiredGuestCaps
;
3123 fSessionRemovedCaps
= fCurrentOwnedCaps
& fNotMask
;
3124 fSessionAddedCaps
= fOrMask
& ~fCurrentOwnedCaps
;
3125 fOtherConflictingCaps
= pDevExt
->fAcquiredGuestCaps
& ~fCurrentOwnedCaps
;
3126 fOtherConflictingCaps
&= fSessionAddedCaps
;
3128 if (!fOtherConflictingCaps
)
3130 if (fSessionAddedCaps
)
3132 pSession
->fAcquiredGuestCaps
|= fSessionAddedCaps
;
3133 pDevExt
->fAcquiredGuestCaps
|= fSessionAddedCaps
;
3136 if (fSessionRemovedCaps
)
3138 pSession
->fAcquiredGuestCaps
&= ~fSessionRemovedCaps
;
3139 pDevExt
->fAcquiredGuestCaps
&= ~fSessionRemovedCaps
;
3143 * If something changes (which is very likely), tell the host.
3145 if (fSessionAddedCaps
|| fSessionRemovedCaps
|| pDevExt
->fGuestCapsHost
== UINT32_MAX
)
3147 Assert(pReq
|| fSessionTermination
);
3150 rc
= vgdrvUpdateCapabilitiesOnHostWithReqAndLock(pDevExt
, pReq
);
3151 if (RT_FAILURE(rc
) && !fSessionTermination
)
3153 /* Failed, roll back. */
3154 if (fSessionAddedCaps
)
3156 pSession
->fAcquiredGuestCaps
&= ~fSessionAddedCaps
;
3157 pDevExt
->fAcquiredGuestCaps
&= ~fSessionAddedCaps
;
3159 if (fSessionRemovedCaps
)
3161 pSession
->fAcquiredGuestCaps
|= fSessionRemovedCaps
;
3162 pDevExt
->fAcquiredGuestCaps
|= fSessionRemovedCaps
;
3165 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3166 LogRel(("vgdrvAcquireSessionCapabilities: vgdrvUpdateCapabilitiesOnHostWithReqAndLock failed: rc=%Rrc\n", rc
));
3167 VbglGRFree(&pReq
->header
);
3175 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3177 Log(("vgdrvAcquireSessionCapabilities: Caps %#x were busy\n", fOtherConflictingCaps
));
3178 VbglGRFree(&pReq
->header
);
3179 return VERR_RESOURCE_BUSY
;
3182 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3184 VbglGRFree(&pReq
->header
);
3187 * If we added a capability, check if that means some other thread in our
3188 * session should be unblocked because there are events pending.
3190 * HACK ALERT! When the seamless support capability is added we generate a
3191 * seamless change event so that the ring-3 client can sync with
3192 * the seamless state. Although this introduces a spurious
3193 * wakeups of the ring-3 client, it solves the problem of client
3194 * state inconsistency in multiuser environment (on Windows).
3196 if (fSessionAddedCaps
)
3198 uint32_t fGenFakeEvents
= 0;
3199 if (fSessionAddedCaps
& VMMDEV_GUEST_SUPPORTS_SEAMLESS
)
3200 fGenFakeEvents
|= VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST
;
3202 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
3203 if (fGenFakeEvents
|| pDevExt
->f32PendingEvents
)
3204 vgdrvDispatchEventsLocked(pDevExt
, fGenFakeEvents
);
3205 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3207 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
3208 VGDrvCommonWaitDoWakeUps(pDevExt
);
3212 return VINF_SUCCESS
;
3217 * Handle VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE.
3219 * @returns VBox status code.
3221 * @param pDevExt The device extension.
3222 * @param pSession The session.
3223 * @param pAcquire The request.
3225 static int vgdrvIoCtl_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, VBoxGuestCapsAquire
*pAcquire
)
3228 LogFlow(("VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE: or=%#x not=%#x flags=%#x\n",
3229 pAcquire
->u32OrMask
, pAcquire
->u32NotMask
, pAcquire
->enmFlags
));
3231 rc
= vgdrvAcquireSessionCapabilities(pDevExt
, pSession
, pAcquire
->u32OrMask
, pAcquire
->u32NotMask
, pAcquire
->enmFlags
,
3232 false /*fSessionTermination*/);
3234 LogRel(("VGDrvCommonIoCtl: GUEST_CAPS_ACQUIRE failed rc=%Rrc\n", rc
));
3236 return VINF_SUCCESS
;
3241 * Sets the guest capabilities for a session.
3243 * @returns VBox status code.
3244 * @param pDevExt The device extension.
3245 * @param pSession The session.
3246 * @param fOrMask The capabilities to add.
3247 * @param fNotMask The capabilities to remove.
3248 * @param fSessionTermination Set if we're called by the session cleanup code.
3249 * This tweaks the error handling so we perform
3250 * proper session cleanup even if the host
3253 * @remarks Takes the session spinlock.
3255 static int vgdrvSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
3256 uint32_t fOrMask
, uint32_t fNotMask
, bool fSessionTermination
)
3259 * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
3261 VMMDevReqGuestCapabilities2
*pReq
;
3262 int rc
= VbglGRAlloc((VMMDevRequestHeader
**)&pReq
, sizeof(*pReq
), VMMDevReq_SetGuestCapabilities
);
3265 else if (!fSessionTermination
)
3267 LogRel(("vgdrvSetSessionCapabilities: VbglGRAlloc failure: %Rrc\n", rc
));
3271 pReq
= NULL
; /* Ignore failure, we must do session cleanup. */
3274 RTSpinlockAcquire(pDevExt
->SessionSpinlock
);
3276 #ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
3278 * Capabilities in "acquire" mode cannot be set via this API.
3279 * (Acquire mode is only used on windows at the time of writing.)
3281 if (!(fOrMask
& pDevExt
->fAcquireModeGuestCaps
))
3285 * Apply the changes to the session mask.
3288 uint32_t fPrevious
= pSession
->fCapabilities
;
3289 pSession
->fCapabilities
|= fOrMask
;
3290 pSession
->fCapabilities
&= ~fNotMask
;
3293 * If anything actually changed, update the global usage counters.
3295 fChanged
= fPrevious
^ pSession
->fCapabilities
;
3298 bool fGlobalChange
= vgdrvBitUsageTrackerChange(&pDevExt
->SetGuestCapsTracker
, fChanged
, fPrevious
,
3299 pDevExt
->cSessions
, "SetGuestCapsTracker");
3302 * If there are global changes, update the capabilities on the host.
3304 if (fGlobalChange
|| pDevExt
->fGuestCapsHost
== UINT32_MAX
)
3306 Assert(pReq
|| fSessionTermination
);
3309 rc
= vgdrvUpdateCapabilitiesOnHostWithReqAndLock(pDevExt
, pReq
);
3311 /* On failure, roll back (unless it's session termination time). */
3312 if (RT_FAILURE(rc
) && !fSessionTermination
)
3314 vgdrvBitUsageTrackerChange(&pDevExt
->SetGuestCapsTracker
, fChanged
, pSession
->fCapabilities
,
3315 pDevExt
->cSessions
, "SetGuestCapsTracker");
3316 pSession
->fCapabilities
= fPrevious
;
3322 #ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
3324 rc
= VERR_RESOURCE_BUSY
;
3327 RTSpinlockRelease(pDevExt
->SessionSpinlock
);
3329 VbglGRFree(&pReq
->header
);
3335 * Handle VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES.
3337 * @returns VBox status code.
3339 * @param pDevExt The device extension.
3340 * @param pSession The session.
3341 * @param pInfo The request.
3343 static int vgdrvIoCtl_SetCapabilities(PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
, VBoxGuestSetCapabilitiesInfo
*pInfo
)
3346 LogFlow(("VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES: or=%#x not=%#x\n", pInfo
->u32OrMask
, pInfo
->u32NotMask
));
3348 if (!((pInfo
->u32OrMask
| pInfo
->u32NotMask
) & ~VMMDEV_GUEST_CAPABILITIES_MASK
))
3349 rc
= vgdrvSetSessionCapabilities(pDevExt
, pSession
, pInfo
->u32OrMask
, pInfo
->u32NotMask
, false /*fSessionTermination*/);
3351 rc
= VERR_INVALID_PARAMETER
;
3360 * Common IOCtl for user to kernel and kernel to kernel communication.
3362 * This function only does the basic validation and then invokes
3363 * worker functions that takes care of each specific function.
3365 * @returns VBox status code.
3367 * @param iFunction The requested function.
3368 * @param pDevExt The device extension.
3369 * @param pSession The client session.
3370 * @param pvData The input/output data buffer. Can be NULL depending on the function.
3371 * @param cbData The max size of the data buffer.
3372 * @param pcbDataReturned Where to store the amount of returned data. Can be NULL.
3374 int VGDrvCommonIoCtl(unsigned iFunction
, PVBOXGUESTDEVEXT pDevExt
, PVBOXGUESTSESSION pSession
,
3375 void *pvData
, size_t cbData
, size_t *pcbDataReturned
)
3378 LogFlow(("VGDrvCommonIoCtl: iFunction=%#x pDevExt=%p pSession=%p pvData=%p cbData=%zu\n",
3379 iFunction
, pDevExt
, pSession
, pvData
, cbData
));
3382 * Make sure the returned data size is set to zero.
3384 if (pcbDataReturned
)
3385 *pcbDataReturned
= 0;
3388 * Define some helper macros to simplify validation.
3390 #define CHECKRET_RING0(mnemonic) \
3392 if (pSession->R0Process != NIL_RTR0PROCESS) \
3394 LogFunc((mnemonic ": Ring-0 only, caller is %RTproc/%p\n", \
3395 pSession->Process, (uintptr_t)pSession->R0Process)); \
3396 return VERR_PERMISSION_DENIED; \
3399 #define CHECKRET_MIN_SIZE(mnemonic, cbMin) \
3401 if (cbData < (cbMin)) \
3403 LogFunc((mnemonic ": cbData=%#zx (%zu) min is %#zx (%zu)\n", \
3404 cbData, cbData, (size_t)(cbMin), (size_t)(cbMin))); \
3405 return VERR_BUFFER_OVERFLOW; \
3407 if ((cbMin) != 0 && !VALID_PTR(pvData)) \
3409 LogFunc((mnemonic ": Invalid pointer %p\n", pvData)); \
3410 return VERR_INVALID_POINTER; \
3413 #define CHECKRET_SIZE(mnemonic, cb) \
3415 if (cbData != (cb)) \
3417 LogFunc((mnemonic ": cbData=%#zx (%zu) expected is %#zx (%zu)\n", \
3418 cbData, cbData, (size_t)(cb), (size_t)(cb))); \
3419 return VERR_BUFFER_OVERFLOW; \
3421 if ((cb) != 0 && !VALID_PTR(pvData)) \
3423 LogFunc((mnemonic ": Invalid pointer %p\n", pvData)); \
3424 return VERR_INVALID_POINTER; \
3430 * Deal with variably sized requests first.
3433 if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0)))
3435 CHECKRET_MIN_SIZE("VMMREQUEST", sizeof(VMMDevRequestHeader
));
3436 rc
= vgdrvIoCtl_VMMRequest(pDevExt
, pSession
, (VMMDevRequestHeader
*)pvData
, cbData
, pcbDataReturned
);
3438 #ifdef VBOX_WITH_HGCM
3440 * These ones are a bit tricky.
3442 else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0)))
3444 bool fInterruptible
= pSession
->R0Process
!= NIL_RTR0PROCESS
;
3445 CHECKRET_MIN_SIZE("HGCM_CALL", sizeof(VBoxGuestHGCMCallInfo
));
3446 rc
= vgdrvIoCtl_HGCMCall(pDevExt
, pSession
, (VBoxGuestHGCMCallInfo
*)pvData
, RT_INDEFINITE_WAIT
,
3447 fInterruptible
, false /*f32bit*/, false /* fUserData */,
3448 0, cbData
, pcbDataReturned
);
3450 else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0)))
3452 VBoxGuestHGCMCallInfoTimed
*pInfo
= (VBoxGuestHGCMCallInfoTimed
*)pvData
;
3453 CHECKRET_MIN_SIZE("HGCM_CALL_TIMED", sizeof(VBoxGuestHGCMCallInfoTimed
));
3454 rc
= vgdrvIoCtl_HGCMCall(pDevExt
, pSession
, &pInfo
->info
, pInfo
->u32Timeout
,
3455 !!pInfo
->fInterruptible
|| pSession
->R0Process
!= NIL_RTR0PROCESS
,
3456 false /*f32bit*/, false /* fUserData */,
3457 RT_OFFSETOF(VBoxGuestHGCMCallInfoTimed
, info
), cbData
, pcbDataReturned
);
3459 else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_USERDATA(0)))
3461 bool fInterruptible
= true;
3462 CHECKRET_MIN_SIZE("HGCM_CALL", sizeof(VBoxGuestHGCMCallInfo
));
3463 rc
= vgdrvIoCtl_HGCMCall(pDevExt
, pSession
, (VBoxGuestHGCMCallInfo
*)pvData
, RT_INDEFINITE_WAIT
,
3464 fInterruptible
, false /*f32bit*/, true /* fUserData */,
3465 0, cbData
, pcbDataReturned
);
3467 # ifdef RT_ARCH_AMD64
3468 else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_32(0)))
3470 bool fInterruptible
= pSession
->R0Process
!= NIL_RTR0PROCESS
;
3471 CHECKRET_MIN_SIZE("HGCM_CALL", sizeof(VBoxGuestHGCMCallInfo
));
3472 rc
= vgdrvIoCtl_HGCMCall(pDevExt
, pSession
, (VBoxGuestHGCMCallInfo
*)pvData
, RT_INDEFINITE_WAIT
,
3473 fInterruptible
, true /*f32bit*/, false /* fUserData */,
3474 0, cbData
, pcbDataReturned
);
3476 else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED_32(0)))
3478 CHECKRET_MIN_SIZE("HGCM_CALL_TIMED", sizeof(VBoxGuestHGCMCallInfoTimed
));
3479 VBoxGuestHGCMCallInfoTimed
*pInfo
= (VBoxGuestHGCMCallInfoTimed
*)pvData
;
3480 rc
= vgdrvIoCtl_HGCMCall(pDevExt
, pSession
, &pInfo
->info
, pInfo
->u32Timeout
,
3481 !!pInfo
->fInterruptible
|| pSession
->R0Process
!= NIL_RTR0PROCESS
,
3482 true /*f32bit*/, false /* fUserData */,
3483 RT_OFFSETOF(VBoxGuestHGCMCallInfoTimed
, info
), cbData
, pcbDataReturned
);
3486 #endif /* VBOX_WITH_HGCM */
3487 else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0)))
3489 CHECKRET_MIN_SIZE("LOG", 1);
3490 rc
= vgdrvIoCtl_Log(pDevExt
, (char *)pvData
, cbData
, pcbDataReturned
, pSession
->fUserSession
);
3496 case VBOXGUEST_IOCTL_GETVMMDEVPORT
:
3497 CHECKRET_RING0("GETVMMDEVPORT");
3498 CHECKRET_MIN_SIZE("GETVMMDEVPORT", sizeof(VBoxGuestPortInfo
));
3499 rc
= vgdrvIoCtl_GetVMMDevPort(pDevExt
, (VBoxGuestPortInfo
*)pvData
, pcbDataReturned
);
3502 #ifndef RT_OS_WINDOWS /* Windows has its own implementation of this. */
3503 case VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK
:
3504 CHECKRET_RING0("SET_MOUSE_NOTIFY_CALLBACK");
3505 CHECKRET_SIZE("SET_MOUSE_NOTIFY_CALLBACK", sizeof(VBoxGuestMouseSetNotifyCallback
));
3506 rc
= vgdrvIoCtl_SetMouseNotifyCallback(pDevExt
, (VBoxGuestMouseSetNotifyCallback
*)pvData
);
3510 case VBOXGUEST_IOCTL_WAITEVENT
:
3511 CHECKRET_MIN_SIZE("WAITEVENT", sizeof(VBoxGuestWaitEventInfo
));
3512 rc
= vgdrvIoCtl_WaitEvent(pDevExt
, pSession
, (VBoxGuestWaitEventInfo
*)pvData
,
3513 pcbDataReturned
, pSession
->R0Process
!= NIL_RTR0PROCESS
);
3516 case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS
:
3517 CHECKRET_SIZE("CANCEL_ALL_WAITEVENTS", 0);
3518 rc
= vgdrvIoCtl_CancelAllWaitEvents(pDevExt
, pSession
);
3521 case VBOXGUEST_IOCTL_CTL_FILTER_MASK
:
3522 CHECKRET_MIN_SIZE("CTL_FILTER_MASK", sizeof(VBoxGuestFilterMaskInfo
));
3523 rc
= vgdrvIoCtl_CtlFilterMask(pDevExt
, pSession
, (VBoxGuestFilterMaskInfo
*)pvData
);
3526 #ifdef VBOX_WITH_HGCM
3527 case VBOXGUEST_IOCTL_HGCM_CONNECT
:
3528 # ifdef RT_ARCH_AMD64
3529 case VBOXGUEST_IOCTL_HGCM_CONNECT_32
:
3531 CHECKRET_MIN_SIZE("HGCM_CONNECT", sizeof(VBoxGuestHGCMConnectInfo
));
3532 rc
= vgdrvIoCtl_HGCMConnect(pDevExt
, pSession
, (VBoxGuestHGCMConnectInfo
*)pvData
, pcbDataReturned
);
3535 case VBOXGUEST_IOCTL_HGCM_DISCONNECT
:
3536 # ifdef RT_ARCH_AMD64
3537 case VBOXGUEST_IOCTL_HGCM_DISCONNECT_32
:
3539 CHECKRET_MIN_SIZE("HGCM_DISCONNECT", sizeof(VBoxGuestHGCMDisconnectInfo
));
3540 rc
= vgdrvIoCtl_HGCMDisconnect(pDevExt
, pSession
, (VBoxGuestHGCMDisconnectInfo
*)pvData
, pcbDataReturned
);
3542 #endif /* VBOX_WITH_HGCM */
3544 case VBOXGUEST_IOCTL_CHECK_BALLOON
:
3545 CHECKRET_MIN_SIZE("CHECK_MEMORY_BALLOON", sizeof(VBoxGuestCheckBalloonInfo
));
3546 rc
= vgdrvIoCtl_CheckMemoryBalloon(pDevExt
, pSession
, (VBoxGuestCheckBalloonInfo
*)pvData
, pcbDataReturned
);
3549 case VBOXGUEST_IOCTL_CHANGE_BALLOON
:
3550 CHECKRET_MIN_SIZE("CHANGE_MEMORY_BALLOON", sizeof(VBoxGuestChangeBalloonInfo
));
3551 rc
= vgdrvIoCtl_ChangeMemoryBalloon(pDevExt
, pSession
, (VBoxGuestChangeBalloonInfo
*)pvData
, pcbDataReturned
);
3554 case VBOXGUEST_IOCTL_WRITE_CORE_DUMP
:
3555 CHECKRET_MIN_SIZE("WRITE_CORE_DUMP", sizeof(VBoxGuestWriteCoreDump
));
3556 rc
= vgdrvIoCtl_WriteCoreDump(pDevExt
, (VBoxGuestWriteCoreDump
*)pvData
);
3559 case VBOXGUEST_IOCTL_SET_MOUSE_STATUS
:
3560 CHECKRET_SIZE("SET_MOUSE_STATUS", sizeof(uint32_t));
3561 rc
= vgdrvIoCtl_SetMouseStatus(pDevExt
, pSession
, *(uint32_t *)pvData
);
3564 #ifdef VBOX_WITH_DPC_LATENCY_CHECKER
3565 case VBOXGUEST_IOCTL_DPC_LATENCY_CHECKER
:
3566 CHECKRET_SIZE("DPC_LATENCY_CHECKER", 0);
3567 rc
= VGDrvNtIOCtl_DpcLatencyChecker();
3571 case VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE
:
3572 CHECKRET_SIZE("GUEST_CAPS_ACQUIRE", sizeof(VBoxGuestCapsAquire
));
3573 rc
= vgdrvIoCtl_GuestCapsAcquire(pDevExt
, pSession
, (VBoxGuestCapsAquire
*)pvData
);
3574 *pcbDataReturned
= sizeof(VBoxGuestCapsAquire
);
3577 case VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES
:
3578 CHECKRET_MIN_SIZE("SET_GUEST_CAPABILITIES", sizeof(VBoxGuestSetCapabilitiesInfo
));
3579 rc
= vgdrvIoCtl_SetCapabilities(pDevExt
, pSession
, (VBoxGuestSetCapabilitiesInfo
*)pvData
);
3584 LogRel(("VGDrvCommonIoCtl: Unknown request iFunction=%#x stripped size=%#x\n",
3585 iFunction
, VBOXGUEST_IOCTL_STRIP_SIZE(iFunction
)));
3586 rc
= VERR_NOT_SUPPORTED
;
3592 LogFlow(("VGDrvCommonIoCtl: returns %Rrc *pcbDataReturned=%zu\n", rc
, pcbDataReturned
? *pcbDataReturned
: 0));
3598 * Used by VGDrvCommonISR as well as the acquire guest capability code.
3600 * @returns VINF_SUCCESS on success. On failure, ORed together
3601 * RTSemEventMultiSignal errors (completes processing despite errors).
3602 * @param pDevExt The VBoxGuest device extension.
3603 * @param fEvents The events to dispatch.
3605 static int vgdrvDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt
, uint32_t fEvents
)
3607 PVBOXGUESTWAIT pWait
;
3608 PVBOXGUESTWAIT pSafe
;
3609 int rc
= VINF_SUCCESS
;
3611 fEvents
|= pDevExt
->f32PendingEvents
;
3613 RTListForEachSafe(&pDevExt
->WaitList
, pWait
, pSafe
, VBOXGUESTWAIT
, ListNode
)
3615 uint32_t fHandledEvents
= pWait
->fReqEvents
& fEvents
;
3616 if ( fHandledEvents
!= 0
3617 && !pWait
->fResEvents
)
3619 /* Does this one wait on any of the events we're dispatching? We do a quick
3620 check first, then deal with VBOXGUEST_ACQUIRE_STYLE_EVENTS as applicable. */
3621 if (fHandledEvents
& VBOXGUEST_ACQUIRE_STYLE_EVENTS
)
3622 fHandledEvents
&= vgdrvGetAllowedEventMaskForSession(pDevExt
, pWait
->pSession
);
3625 pWait
->fResEvents
= pWait
->fReqEvents
& fEvents
& fHandledEvents
;
3626 fEvents
&= ~pWait
->fResEvents
;
3627 RTListNodeRemove(&pWait
->ListNode
);
3628 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
3629 RTListAppend(&pDevExt
->WakeUpList
, &pWait
->ListNode
);
3631 RTListAppend(&pDevExt
->WokenUpList
, &pWait
->ListNode
);
3632 rc
|= RTSemEventMultiSignal(pWait
->Event
);
3640 ASMAtomicWriteU32(&pDevExt
->f32PendingEvents
, fEvents
);
3646 * Simply checks whether the IRQ is ours or not, does not do any interrupt
3649 * @returns true if it was our interrupt, false if it wasn't.
3650 * @param pDevExt The VBoxGuest device extension.
3652 bool VGDrvCommonIsOurIRQ(PVBOXGUESTDEVEXT pDevExt
)
3654 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
3655 bool const fOurIrq
= pDevExt
->pVMMDevMemory
->V
.V1_04
.fHaveEvents
;
3656 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3663 * Common interrupt service routine.
3665 * This deals with events and with waking up thread waiting for those events.
3667 * @returns true if it was our interrupt, false if it wasn't.
3668 * @param pDevExt The VBoxGuest device extension.
3670 bool VGDrvCommonISR(PVBOXGUESTDEVEXT pDevExt
)
3672 VMMDevEvents
volatile *pReq
= pDevExt
->pIrqAckEvents
;
3673 bool fMousePositionChanged
= false;
3678 * Make sure we've initialized the device extension.
3680 if (RT_UNLIKELY(!pReq
))
3684 * Enter the spinlock and check if it's our IRQ or not.
3686 RTSpinlockAcquire(pDevExt
->EventSpinlock
);
3687 fOurIrq
= pDevExt
->pVMMDevMemory
->V
.V1_04
.fHaveEvents
;
3691 * Acknowlegde events.
3692 * We don't use VbglGRPerform here as it may take another spinlocks.
3694 pReq
->header
.rc
= VERR_INTERNAL_ERROR
;
3696 ASMCompilerBarrier();
3697 ASMOutU32(pDevExt
->IOPortBase
+ VMMDEV_PORT_OFF_REQUEST
, (uint32_t)pDevExt
->PhysIrqAckEvents
);
3698 ASMCompilerBarrier(); /* paranoia */
3699 if (RT_SUCCESS(pReq
->header
.rc
))
3701 uint32_t fEvents
= pReq
->events
;
3703 Log3(("VGDrvCommonISR: acknowledge events succeeded %#RX32\n", fEvents
));
3706 * VMMDEV_EVENT_MOUSE_POSITION_CHANGED can only be polled for.
3708 if (fEvents
& VMMDEV_EVENT_MOUSE_POSITION_CHANGED
)
3710 fMousePositionChanged
= true;
3711 fEvents
&= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED
;
3712 #if !defined(RT_OS_WINDOWS) && !defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT)
3713 if (pDevExt
->MouseNotifyCallback
.pfnNotify
)
3714 pDevExt
->MouseNotifyCallback
.pfnNotify(pDevExt
->MouseNotifyCallback
.pvUser
);
3718 #ifdef VBOX_WITH_HGCM
3720 * The HGCM event/list is kind of different in that we evaluate all entries.
3722 if (fEvents
& VMMDEV_EVENT_HGCM
)
3724 PVBOXGUESTWAIT pWait
;
3725 PVBOXGUESTWAIT pSafe
;
3726 RTListForEachSafe(&pDevExt
->HGCMWaitList
, pWait
, pSafe
, VBOXGUESTWAIT
, ListNode
)
3728 if (pWait
->pHGCMReq
->fu32Flags
& VBOX_HGCM_REQ_DONE
)
3730 pWait
->fResEvents
= VMMDEV_EVENT_HGCM
;
3731 RTListNodeRemove(&pWait
->ListNode
);
3732 # ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
3733 RTListAppend(&pDevExt
->WakeUpList
, &pWait
->ListNode
);
3735 RTListAppend(&pDevExt
->WokenUpList
, &pWait
->ListNode
);
3736 rc
|= RTSemEventMultiSignal(pWait
->Event
);
3740 fEvents
&= ~VMMDEV_EVENT_HGCM
;
3745 * Normal FIFO waiter evaluation.
3747 rc
|= vgdrvDispatchEventsLocked(pDevExt
, fEvents
);
3749 else /* something is serious wrong... */
3750 Log(("VGDrvCommonISR: acknowledge events failed rc=%Rrc (events=%#x)!!\n",
3751 pReq
->header
.rc
, pReq
->events
));
3754 Log3(("VGDrvCommonISR: not ours\n"));
3756 RTSpinlockRelease(pDevExt
->EventSpinlock
);
3759 * Execute the mouse notification callback here if it cannot be executed while
3760 * holding the interrupt safe spinlock, see @bugref{8639}.
3762 #if defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT)
3763 if ( fMousePositionChanged
3764 && pDevExt
->MouseNotifyCallback
.pfnNotify
)
3765 pDevExt
->MouseNotifyCallback
.pfnNotify(pDevExt
->MouseNotifyCallback
.pvUser
);
3768 #if defined(VBOXGUEST_USE_DEFERRED_WAKE_UP) && !defined(RT_OS_DARWIN) && !defined(RT_OS_WINDOWS)
3771 * Note. On Windows this isn't possible at this IRQL, so a DPC will take
3772 * care of it. Same on darwin, doing it in the work loop callback.
3774 VGDrvCommonWaitDoWakeUps(pDevExt
);
3778 * Work the poll and async notification queues on OSes that implements that.
3779 * (Do this outside the spinlock to prevent some recursive spinlocking.)
3781 if (fMousePositionChanged
)
3783 ASMAtomicIncU32(&pDevExt
->u32MousePosChangedSeq
);
3784 VGDrvNativeISRMousePollEvent(pDevExt
);