diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-master.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp')
-rw-r--r-- | src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp | 343 |
1 files changed, 309 insertions, 34 deletions
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp index 594e0921..b1ffd3ba 100644 --- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp +++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2007-2012 Oracle Corporation + * Copyright (C) 2007-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -54,7 +54,7 @@ # include <Windows.h> # endif #endif -#if defined(RT_OS_SOLARIS) +#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN) # include <iprt/rand.h> #endif @@ -70,17 +70,61 @@ static void testSetMouseStatus(void); #endif static int VBoxGuestCommonIOCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fFeatures); -#ifdef VBOX_WITH_DPC_LATENCY_CHECKER -int VBoxGuestCommonIOCtl_DPC(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, - void *pvData, size_t cbData, size_t *pcbDataReturned); -#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */ +static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags); + +#define VBOXGUEST_ACQUIRE_STYLE_EVENTS (VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST) + +DECLINLINE(uint32_t) VBoxGuestCommonGetHandledEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession) +{ + if (!pDevExt->u32AcquireModeGuestCaps) + return VMMDEV_EVENT_VALID_EVENT_MASK; + + uint32_t u32AllowedGuestCaps = pSession->u32AquiredGuestCaps | (VMMDEV_EVENT_VALID_EVENT_MASK & ~pDevExt->u32AcquireModeGuestCaps); + uint32_t u32CleanupEvents = VBOXGUEST_ACQUIRE_STYLE_EVENTS; + if (u32AllowedGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS) + u32CleanupEvents &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST; + if (u32AllowedGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS) + u32CleanupEvents &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; + + return VMMDEV_EVENT_VALID_EVENT_MASK & ~u32CleanupEvents; +} + +DECLINLINE(uint32_t) VBoxGuestCommonGetAndCleanPendingEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fReqEvents) +{ + uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents & VBoxGuestCommonGetHandledEventsLocked(pDevExt, pSession); + if (fMatches) + ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches); + return fMatches; +} + +DECLINLINE(bool) VBoxGuestCommonGuestCapsModeSet(PVBOXGUESTDEVEXT pDevExt, uint32_t fCaps, bool fAcquire, uint32_t *pu32OtherVal) +{ + uint32_t *pVal = fAcquire ? &pDevExt->u32AcquireModeGuestCaps : &pDevExt->u32SetModeGuestCaps; + const uint32_t fNotVal = !fAcquire ? pDevExt->u32AcquireModeGuestCaps : pDevExt->u32SetModeGuestCaps; + bool fResult = true; + RTSpinlockAcquire(pDevExt->EventSpinlock); + + if (!(fNotVal & fCaps)) + *pVal |= fCaps; + else + { + AssertMsgFailed(("trying to change caps mode\n")); + fResult = false; + } + + RTSpinlockReleaseNoInts(pDevExt->EventSpinlock); + + if (pu32OtherVal) + *pu32OtherVal = fNotVal; + return fResult; +} /******************************************************************************* * Global Variables * *******************************************************************************/ static const size_t cbChangeMemBalloonReq = RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]); -#if defined(RT_OS_SOLARIS) +#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) /** * Drag in the rest of IRPT since we share it with the * rest of the kernel modules on Solaris. @@ -100,7 +144,7 @@ PFNRT g_apfnVBoxGuestIPRTDeps[] = (PFNRT)RTSemMutexIsOwned, NULL }; -#endif /* RT_OS_SOLARIS */ +#endif /* RT_OS_DARWIN || RT_OS_SOLARIS */ /** @@ -418,7 +462,7 @@ static int vboxGuestSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt, uint32_t cBal pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAllocZ(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks); if (!pDevExt->MemBalloon.paMemObj) { - LogRel(("VBoxGuestSetBalloonSizeKernel: no memory for paMemObj!\n")); + LogRel(("vboxGuestSetBalloonSizeKernel: no memory for paMemObj!\n")); return VERR_NO_MEMORY; } } @@ -706,6 +750,20 @@ int VBoxGuestInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase, int rc, rc2; unsigned i; +#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER + /* + * Create the release log. + */ + static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES; + PRTLOGGER pRelLogger; + rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all", + "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL); + if (RT_SUCCESS(rc)) + RTLogRelSetDefaultInstance(pRelLogger); + /** @todo Add native hook for getting logger config parameters and setting + * them. On linux we should use the module parameter stuff... */ +#endif + /* * Adjust fFixedEvents. */ @@ -772,6 +830,10 @@ int VBoxGuestInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase, pVMMDev->u32Version, VMMDEV_MEMORY_VERSION, pVMMDev->u32Size, cbMMIO)); } + pDevExt->u32AcquireModeGuestCaps = 0; + pDevExt->u32SetModeGuestCaps = 0; + pDevExt->u32GuestCaps = 0; + /* * Create the wait and session spinlocks as well as the ballooning mutex. */ @@ -856,6 +918,11 @@ int VBoxGuestInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase, rc2 = RTSemFastMutexDestroy(pDevExt->MemBalloon.hMtx); AssertRC(rc2); rc2 = RTSpinlockDestroy(pDevExt->EventSpinlock); AssertRC(rc2); rc2 = RTSpinlockDestroy(pDevExt->SessionSpinlock); AssertRC(rc2); + +#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER + RTLogDestroy(RTLogRelSetDefaultInstance(NULL)); + RTLogDestroy(RTLogSetDefaultInstance(NULL)); +#endif return rc; /* (failed) */ } @@ -925,6 +992,12 @@ void VBoxGuestDeleteDevExt(PVBOXGUESTDEVEXT pDevExt) pDevExt->IOPortBase = 0; pDevExt->pIrqAckEvents = NULL; + +#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER + RTLogDestroy(RTLogRelSetDefaultInstance(NULL)); + RTLogDestroy(RTLogSetDefaultInstance(NULL)); +#endif + } @@ -987,7 +1060,7 @@ int VBoxGuestCreateKernelSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *pp return VINF_SUCCESS; } - +static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession); /** * Closes a VBoxGuest session. @@ -1001,6 +1074,10 @@ void VBoxGuestCloseSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession) Log(("VBoxGuestCloseSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n", pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */ + VBoxGuestCommonGuestCapsAcquire(pDevExt, pSession, 0, UINT32_MAX, VBOXGUESTCAPSACQUIRE_FLAGS_NONE); + + VBoxGuestCommonIOCtl_CancelAllWaitEvents(pDevExt, pSession); + #ifdef VBOX_WITH_HGCM for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++) if (pSession->aHGCMClientIds[i]) @@ -1291,13 +1368,12 @@ int VBoxGuestCommonIOCtl_SetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGu * * @returns VINF_SUCCESS if we've left the spinlock and can return immediately. */ -DECLINLINE(int) WaitEventCheckCondition(PVBOXGUESTDEVEXT pDevExt, VBoxGuestWaitEventInfo *pInfo, +DECLINLINE(int) WaitEventCheckCondition(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestWaitEventInfo *pInfo, int iEvent, const uint32_t fReqEvents) { - uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents; + uint32_t fMatches = VBoxGuestCommonGetAndCleanPendingEventsLocked(pDevExt, pSession, fReqEvents); if (fMatches) { - ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches); RTSpinlockReleaseNoInts(pDevExt->EventSpinlock); pInfo->u32EventFlagsOut = fMatches; @@ -1333,7 +1409,7 @@ static int VBoxGuestCommonIOCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSE iEvent = ASMBitFirstSetU32(fReqEvents) - 1; if (RT_UNLIKELY(iEvent < 0)) { - Log(("VBoxGuestCommonIOCtl: WAITEVENT: Invalid input mask %#x!!\n", fReqEvents)); + LogRel(("VBoxGuestCommonIOCtl: WAITEVENT: Invalid input mask %#x!!\n", fReqEvents)); return VERR_INVALID_PARAMETER; } @@ -1341,7 +1417,7 @@ static int VBoxGuestCommonIOCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSE * Check the condition up front, before doing the wait-for-event allocations. */ RTSpinlockAcquire(pDevExt->EventSpinlock); - rc = WaitEventCheckCondition(pDevExt, pInfo, iEvent, fReqEvents); + rc = WaitEventCheckCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents); if (rc == VINF_SUCCESS) return rc; @@ -1364,7 +1440,7 @@ static int VBoxGuestCommonIOCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSE */ RTSpinlockAcquire(pDevExt->EventSpinlock); RTListAppend(&pDevExt->WaitList, &pWait->ListNode); - rc = WaitEventCheckCondition(pDevExt, pInfo, iEvent, fReqEvents); + rc = WaitEventCheckCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents); if (rc == VINF_SUCCESS) { VBoxGuestWaitFreeUnlocked(pDevExt, pWait); @@ -1465,6 +1541,7 @@ static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PV } RTSpinlockReleaseNoInts(pDevExt->EventSpinlock); Assert(rc == 0); + NOREF(rc); #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP VBoxGuestWaitDoWakeUps(pDevExt); @@ -1481,7 +1558,7 @@ static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PV * @param enmType The request type. * @param pReqHdr The request. */ -static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTSESSION pSession, VMMDevRequestType enmType, +static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VMMDevRequestType enmType, VMMDevRequestHeader const *pReqHdr) { /* @@ -1541,12 +1618,34 @@ static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTSESSION pSession, VMMDevReque case VMMDevReq_GetPageSharingStatus: case VMMDevReq_DebugIsPageShared: case VMMDevReq_ReportGuestStats: + case VMMDevReq_ReportGuestUserState: case VMMDevReq_GetStatisticsChangeRequest: case VMMDevReq_ChangeMemBalloon: enmRequired = kLevel_TrustedUsers; break; /* + * Anyone. But not for CapsAcquire mode + */ + case VMMDevReq_SetGuestCapabilities: + { + VMMDevReqGuestCapabilities2 *pCaps = (VMMDevReqGuestCapabilities2*)pReqHdr; + uint32_t fAcquireCaps = 0; + if (!VBoxGuestCommonGuestCapsModeSet(pDevExt, pCaps->u32OrMask, false, &fAcquireCaps)) + { + AssertFailed(); + LogRel(("calling caps set for acquired caps %d\n", pCaps->u32OrMask)); + enmRequired = kLevel_NoOne; + break; + } + /* hack to adjust the notcaps. + * @todo: move to a better place + * user-mode apps are allowed to pass any mask to the notmask, + * the driver cleans up them accordingly */ + pCaps->u32NotMask &= ~fAcquireCaps; + /* do not break, make it fall through to the below enmRequired setting */ + } + /* * Anyone. */ case VMMDevReq_GetMouseStatus: @@ -1563,11 +1662,11 @@ static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTSESSION pSession, VMMDevReque case VMMDevReq_VideoModeSupported: case VMMDevReq_GetHeightReduction: case VMMDevReq_GetDisplayChangeRequest2: - case VMMDevReq_SetGuestCapabilities: case VMMDevReq_VideoModeSupported2: case VMMDevReq_VideoAccelEnable: case VMMDevReq_VideoAccelFlush: case VMMDevReq_VideoSetVisibleRegion: + case VMMDevReq_GetDisplayChangeRequestEx: case VMMDevReq_GetSeamlessChangeRequest: case VMMDevReq_GetVRDPChangeRequest: case VMMDevReq_LogString: @@ -1641,13 +1740,13 @@ static int VBoxGuestCommonIOCtl_VMMRequest(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTS if (cbReq < cbMinSize) { - Log(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid hdr size %#x, expected >= %#x; type=%#x!!\n", + LogRel(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid hdr size %#x, expected >= %#x; type=%#x!!\n", cbReq, cbMinSize, enmType)); return VERR_INVALID_PARAMETER; } if (cbReq > cbData) { - Log(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid size %#x, expected >= %#x (hdr); type=%#x!!\n", + LogRel(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid size %#x, expected >= %#x (hdr); type=%#x!!\n", cbData, cbReq, enmType)); return VERR_INVALID_PARAMETER; } @@ -1659,7 +1758,7 @@ static int VBoxGuestCommonIOCtl_VMMRequest(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTS return rc; } - rc = VBoxGuestCheckIfVMMReqAllowed(pSession, enmType, pReqHdr); + rc = VBoxGuestCheckIfVMMReqAllowed(pDevExt, pSession, enmType, pReqHdr); if (RT_FAILURE(rc)) { Log(("VBoxGuestCommonIOCtl: VMMREQUEST: Operation not allowed! type=%#x rc=%Rrc\n", enmType, rc)); @@ -1974,7 +2073,7 @@ static int VBoxGuestCommonIOCtl_HGCMCall(PVBOXGUESTDEVEXT pDevExt, if (cbData < cbActual) { LogRel(("VBoxGuestCommonIOCtl: HGCM_CALL: cbData=%#zx (%zu) required size is %#zx (%zu)\n", - cbData, cbActual)); + cbData, cbData, cbActual, cbActual)); return VERR_INVALID_PARAMETER; } @@ -2283,6 +2382,9 @@ static int VBoxGuestCommonIOCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGU RTSpinlockAcquire(pDevExt->SessionSpinlock); + /* For all the bits which the guest is allowed to set, check whether the + * requested value is different to the current one and adjust the global + * usage counter and if appropriate the global state if so. */ for (i = 0; i < sizeof(fFeatures) * 8; i++) { if (RT_BIT_32(i) & VMMDEV_MOUSE_GUEST_MASK) @@ -2417,6 +2519,170 @@ static int VBoxGuestCommonIOCtl_Log(PVBOXGUESTDEVEXT pDevExt, const char *pch, s return VINF_SUCCESS; } +static bool VBoxGuestCommonGuestCapsValidateValues(uint32_t fCaps) +{ + if (fCaps & (~(VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING | VMMDEV_GUEST_SUPPORTS_GRAPHICS))) + return false; + + return true; +} + +static void VBoxGuestCommonCheckEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fGenFakeEvents) +{ + RTSpinlockAcquire(pDevExt->EventSpinlock); + uint32_t fEvents = fGenFakeEvents | pDevExt->f32PendingEvents; + PVBOXGUESTWAIT pWait; + PVBOXGUESTWAIT pSafe; + + RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode) + { + uint32_t fHandledEvents = VBoxGuestCommonGetHandledEventsLocked(pDevExt, pWait->pSession); + if ( (pWait->fReqEvents & fEvents & fHandledEvents) + && !pWait->fResEvents) + { + pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents; + Assert(!(fGenFakeEvents & pWait->fResEvents) || pSession == pWait->pSession); + fEvents &= ~pWait->fResEvents; + RTListNodeRemove(&pWait->ListNode); +#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP + RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode); +#else + RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode); + int rc = RTSemEventMultiSignal(pWait->Event); + AssertRC(rc); +#endif + if (!fEvents) + break; + } + } + ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents); + + RTSpinlockReleaseNoInts(pDevExt->EventSpinlock); + +#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP + VBoxGuestWaitDoWakeUps(pDevExt); +#endif +} + +static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags) +{ + uint32_t fSetCaps = 0; + + if (!VBoxGuestCommonGuestCapsValidateValues(fOrMask)) + { + LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid fOrMask\n", + pSession, fOrMask, fNotMask, enmFlags)); + return VERR_INVALID_PARAMETER; + } + + if ( enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE + && enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_NONE) + { + LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid enmFlags %d\n", + pSession, fOrMask, fNotMask, enmFlags)); + return VERR_INVALID_PARAMETER; + } + + if (!VBoxGuestCommonGuestCapsModeSet(pDevExt, fOrMask, true, &fSetCaps)) + { + LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- calling caps acquire for set caps\n", + pSession, fOrMask, fNotMask, enmFlags)); + return VERR_INVALID_STATE; + } + + if (enmFlags & VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE) + { + Log(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- configured acquire caps: 0x%x\n", + pSession, fOrMask, fNotMask, enmFlags)); + return VINF_SUCCESS; + } + + /* the fNotMask no need to have all values valid, + * invalid ones will simply be ignored */ + uint32_t fCurrentOwnedCaps; + uint32_t fSessionNotCaps; + uint32_t fSessionOrCaps; + uint32_t fOtherConflictingCaps; + + fNotMask &= ~fOrMask; + + RTSpinlockAcquire(pDevExt->EventSpinlock); + + fCurrentOwnedCaps = pSession->u32AquiredGuestCaps; + fSessionNotCaps = fCurrentOwnedCaps & fNotMask; + fSessionOrCaps = fOrMask & ~fCurrentOwnedCaps; + fOtherConflictingCaps = pDevExt->u32GuestCaps & ~fCurrentOwnedCaps; + fOtherConflictingCaps &= fSessionOrCaps; + + if (!fOtherConflictingCaps) + { + if (fSessionOrCaps) + { + pSession->u32AquiredGuestCaps |= fSessionOrCaps; + pDevExt->u32GuestCaps |= fSessionOrCaps; + } + + if (fSessionNotCaps) + { + pSession->u32AquiredGuestCaps &= ~fSessionNotCaps; + pDevExt->u32GuestCaps &= ~fSessionNotCaps; + } + } + + RTSpinlockReleaseNoInts(pDevExt->EventSpinlock); + + if (fOtherConflictingCaps) + { + Log(("VBoxGuest: Caps 0x%x were busy\n", fOtherConflictingCaps)); + return VERR_RESOURCE_BUSY; + } + + /* now do host notification outside the lock */ + if (!fSessionOrCaps && !fSessionNotCaps) + { + /* no changes, return */ + return VINF_SUCCESS; + } + + int rc = VBoxGuestSetGuestCapabilities(fSessionOrCaps, fSessionNotCaps); + if (RT_FAILURE(rc)) + { + LogRel(("VBoxGuestCommonGuestCapsAcquire: VBoxGuestSetGuestCapabilities failed, rc=%Rrc\n", rc)); + + /* Failure branch + * this is generally bad since e.g. failure to release the caps may result in other sessions not being able to use it + * so we are not trying to restore the caps back to their values before the VBoxGuestCommonGuestCapsAcquire call, + * but just pretend everithing is OK. + * @todo: better failure handling mechanism? */ + } + + /* success! */ + uint32_t fGenFakeEvents = 0; + + if (fSessionOrCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS) + { + /* generate the seamless change event so that the r3 app could synch with the seamless state + * although this introduces a false alarming of r3 client, it still solve the problem of + * client state inconsistency in multiuser environment */ + fGenFakeEvents |= VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; + } + + /* since the acquire filter mask has changed, we need to process events in any way to ensure they go from pending events field + * to the proper (un-filtered) entries */ + VBoxGuestCommonCheckEvents(pDevExt, pSession, fGenFakeEvents); + + return VINF_SUCCESS; +} + +static int VBoxGuestCommonIOCTL_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestCapsAquire *pAcquire) +{ + int rc = VBoxGuestCommonGuestCapsAcquire(pDevExt, pSession, pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags); + if (RT_FAILURE(rc)) + LogRel(("VBoxGuestCommonGuestCapsAcquire: failed rc=%Rrc\n", rc)); + pAcquire->rc = rc; + return VINF_SUCCESS; +} + /** * Common IOCtl for user to kernel and kernel to kernel communication. @@ -2477,7 +2743,7 @@ int VBoxGuestCommonIOCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUES if (cbData != (cb)) \ { \ LogFunc((mnemonic ": cbData=%#zx (%zu) expected is %#zx (%zu)\n", \ - cbData, cbData, (size_t)(cb), (size_t)(cb))); \ + cbData, cbData, (size_t)(cb), (size_t)(cb))); \ return VERR_BUFFER_OVERFLOW; \ } \ if ((cb) != 0 && !VALID_PTR(pvData)) \ @@ -2497,12 +2763,6 @@ int VBoxGuestCommonIOCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUES CHECKRET_MIN_SIZE("VMMREQUEST", sizeof(VMMDevRequestHeader)); rc = VBoxGuestCommonIOCtl_VMMRequest(pDevExt, pSession, (VMMDevRequestHeader *)pvData, cbData, pcbDataReturned); } -#ifdef VBOX_WITH_DPC_LATENCY_CHECKER - else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_DPC)) - { - rc = VBoxGuestCommonIOCtl_DPC(pDevExt, pSession, pvData, cbData, pcbDataReturned); - } -#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */ #ifdef VBOX_WITH_HGCM /* * These ones are a bit tricky. @@ -2640,10 +2900,23 @@ int VBoxGuestCommonIOCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUES *(uint32_t *)pvData); break; +#ifdef VBOX_WITH_DPC_LATENCY_CHECKER + case VBOXGUEST_IOCTL_DPC_LATENCY_CHECKER: + CHECKRET_SIZE("DPC_LATENCY_CHECKER", 0); + rc = VbgdNtIOCtl_DpcLatencyChecker(); + break; +#endif + + case VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE: + CHECKRET_SIZE("GUEST_CAPS_ACQUIRE", sizeof(VBoxGuestCapsAquire)); + rc = VBoxGuestCommonIOCTL_GuestCapsAcquire(pDevExt, pSession, (VBoxGuestCapsAquire*)pvData); + *pcbDataReturned = sizeof(VBoxGuestCapsAquire); + break; + default: { - LogRel(("VBoxGuestCommonIOCtl: Unknown request iFunction=%#x Stripped size=%#x\n", iFunction, - VBOXGUEST_IOCTL_STRIP_SIZE(iFunction))); + LogRel(("VBoxGuestCommonIOCtl: Unknown request iFunction=%#x stripped size=%#x\n", + iFunction, VBOXGUEST_IOCTL_STRIP_SIZE(iFunction))); rc = VERR_NOT_SUPPORTED; break; } @@ -2704,7 +2977,7 @@ bool VBoxGuestCommonISR(PVBOXGUESTDEVEXT pDevExt) PVBOXGUESTWAIT pWait; PVBOXGUESTWAIT pSafe; - Log(("VBoxGuestCommonISR: acknowledge events succeeded %#RX32\n", fEvents)); + Log3(("VBoxGuestCommonISR: acknowledge events succeeded %#RX32\n", fEvents)); /* * VMMDEV_EVENT_MOUSE_POSITION_CHANGED can only be polled for. @@ -2748,10 +3021,11 @@ bool VBoxGuestCommonISR(PVBOXGUESTDEVEXT pDevExt) fEvents |= pDevExt->f32PendingEvents; RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode) { - if ( (pWait->fReqEvents & fEvents) + uint32_t fHandledEvents = VBoxGuestCommonGetHandledEventsLocked(pDevExt, pWait->pSession); + if ( (pWait->fReqEvents & fEvents & fHandledEvents) && !pWait->fResEvents) { - pWait->fResEvents = pWait->fReqEvents & fEvents; + pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents; fEvents &= ~pWait->fResEvents; RTListNodeRemove(&pWait->ListNode); #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP @@ -2800,6 +3074,7 @@ bool VBoxGuestCommonISR(PVBOXGUESTDEVEXT pDevExt) ASMAtomicDecU32(&pDevExt->cISR); Assert(rc == 0); + NOREF(rc); return fOurIrq; } |