VirtualBox

Changeset 54601 in vbox for trunk/src/VBox/Additions


Ignore:
Timestamp:
Mar 3, 2015 4:20:06 PM (10 years ago)
Author:
vboxsync
Message:

VBoxGuest: First part of the noisy vboxGuestUpdateHostFlags cleanup.

Location:
trunk/src/VBox/Additions/common/VBoxGuest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp

    r54593 r54601  
    7777{
    7878    HostFlags_FilterMask   = 1,
    79     HostFlags_Capabilities = 2,
    8079    HostFlags_MouseStatus  = 4,
    8180    HostFlags_All          = 7,
     
    9089static DECLCALLBACK(int) VBoxGuestHGCMAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdrNonVolatile, void *pvUser, uint32_t u32User);
    9190#endif
    92 static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask,
    93                                            uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags);
    9491static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
    9592static int      vboxGuestUpdateHostFlags(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, unsigned fFlags);
    96 static uint32_t VBoxGuestCommonGetAndCleanPendingEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fReqEvents);
    97 static uint32_t VBoxGuestCommonGetHandledEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
    98 static bool     VBoxGuestCommonGuestCapsModeSet(PVBOXGUESTDEVEXT pDevExt, uint32_t fCaps, bool fAcquire, uint32_t *pu32OtherVal);
     93static uint32_t vbgdGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
     94static int      vbgdUpdateCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt);
     95static int      vbgdAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask,
     96                                               uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags, bool fSessionTermination);
     97static int      vbgdSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNoMask);
     98static int      vbgdDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents);
    9999
    100100
     
    552552
    553553/**
     554 * Initializes the heartbeat timer.
     555 *
     556 * This feature may be disabled by the host.
     557 *
     558 * @returns VBox status (ignored).
     559 * @param   pDevExt             The device extension.
     560 */
     561static int vbgdHeartbeatInit(PVBOXGUESTDEVEXT pDevExt)
     562{
     563    /*
     564     * Make sure that heartbeat checking is disabled.
     565     */
     566    int rc = VBoxGuestHeartbeatHostConfigure(pDevExt, false);
     567    if (RT_SUCCESS(rc))
     568    {
     569        rc = VBoxGuestHeartbeatHostConfigure(pDevExt, true);
     570        if (RT_SUCCESS(rc))
     571        {
     572            /*
     573             * Preallocate the request to use it from the timer callback because:
     574             *    1) on Windows VbglGRAlloc must be called at IRQL <= APC_LEVEL
     575             *       and the timer callback runs at DISPATCH_LEVEL;
     576             *    2) avoid repeated allocations.
     577             */
     578            rc = VbglGRAlloc(&pDevExt->pReqGuestHeartbeat, sizeof(*pDevExt->pReqGuestHeartbeat), VMMDevReq_GuestHeartbeat);
     579            if (RT_SUCCESS(rc))
     580            {
     581                LogRel(("VBoxGuestInitDevExt: Setting up heartbeat to trigger every %RU64 sec\n",
     582                        pDevExt->cNsHeartbeatInterval / RT_NS_1SEC));
     583                rc = RTTimerCreateEx(&pDevExt->pHeartbeatTimer, pDevExt->cNsHeartbeatInterval, 0 /*fFlags*/,
     584                                     (PFNRTTIMER)VBoxGuestHeartbeatTimerHandler, pDevExt);
     585                if (RT_SUCCESS(rc))
     586                {
     587                    rc = RTTimerStart(pDevExt->pHeartbeatTimer, 0);
     588                    if (RT_SUCCESS(rc))
     589                        return VINF_SUCCESS;
     590
     591                    LogRel(("VBoxGuestInitDevExt: Heartbeat timer failed to start, rc=%Rrc\n", rc));
     592                }
     593                else
     594                    LogRel(("VBoxGuestInitDevExt: Failed to create heartbeat timer: %Rrc\n", rc));
     595
     596                VbglGRFree(pDevExt->pReqGuestHeartbeat);
     597                pDevExt->pReqGuestHeartbeat = NULL;
     598            }
     599            else
     600                LogRel(("VBoxGuestInitDevExt: VbglGRAlloc(VMMDevReq_GuestHeartbeat): %Rrc\n", rc));
     601
     602            LogRel(("VBoxGuestInitDevExt: Failed to set up the timer, guest heartbeat is disabled\n"));
     603            VBoxGuestHeartbeatHostConfigure(pDevExt, false);
     604        }
     605        else
     606            LogRel(("VBoxGuestInitDevExt: Failed to configure host for heartbeat checking: rc=%Rrc\n", rc));
     607    }
     608    return rc;
     609}
     610
     611
     612/**
    554613 * Helper to reinit the VBoxVMM communication after hibernation.
    555614 *
     
    808867    RTListInit(&pDevExt->FreeList);
    809868    RTListInit(&pDevExt->SessionList);
     869    pDevExt->cSessions = 0;
    810870    pDevExt->fLoggingEnabled = false;
    811871    pDevExt->f32PendingEvents = 0;
     
    844904    pDevExt->u32AcquireModeGuestCaps = 0;
    845905    pDevExt->u32SetModeGuestCaps = 0;
    846     pDevExt->u32GuestCaps = 0;
     906    pDevExt->u32GuestCapsAcquired = 0;
     907    RT_ZERO(pDevExt->acGuestCapsSet);
     908    pDevExt->fGuestCapsHost = UINT32_MAX; /* forces a report */
    847909
    848910    /*
     
    886948            if (RT_SUCCESS(rc))
    887949            {
    888                 /* Set the fixed event and disable the guest graphics capability
     950                /*
     951                 * Set the fixed event and disable the guest graphics capability
    889952                 * by default. The guest specific graphics driver will re-enable
    890                  * the graphics capability if and when appropriate. */
    891                 rc = vboxGuestUpdateHostFlags(pDevExt, NULL, HostFlags_FilterMask | HostFlags_Capabilities);
     953                 * the graphics capability if and when appropriate.
     954                 */
     955                rc = vboxGuestUpdateHostFlags(pDevExt, NULL, HostFlags_FilterMask);
    892956                if (RT_SUCCESS(rc))
    893957                {
    894                     vboxGuestInitFixateGuestMappings(pDevExt);
    895 
    896                     rc = VBoxGuestReportDriverStatus(true /* Driver is active */);
    897                     if (RT_FAILURE(rc))
    898                         LogRel(("VBoxGuestInitDevExt: VBoxReportGuestDriverStatus failed, rc=%Rrc\n", rc));
    899 
    900                     /** @todo Move heartbeat initialization into a separate function. */
    901                     /* Make sure that heartbeat checking is disabled. */
    902                     rc = VBoxGuestHeartbeatHostConfigure(pDevExt, false);
     958                    rc = vbgdUpdateCapabilitiesOnHost(pDevExt);
    903959                    if (RT_SUCCESS(rc))
    904960                    {
    905                         rc = VBoxGuestHeartbeatHostConfigure(pDevExt, true);
    906                         if (RT_SUCCESS(rc))
    907                         {
    908                             /* Preallocate the request to use it from the timer callback because:
    909                              *    1) on Windows VbglGRAlloc must be called at IRQL <= APC_LEVEL
    910                              *       and the timer callback runs at DISPATCH_LEVEL;
    911                              *    2) avoid repeated allocations.
    912                              */
    913                             rc = VbglGRAlloc(&pDevExt->pReqGuestHeartbeat, sizeof(*pDevExt->pReqGuestHeartbeat), VMMDevReq_GuestHeartbeat);
    914                             if (RT_FAILURE(rc))
    915                                 LogRel(("VBoxGuestInitDevExt: VbglGRAlloc(VMMDevReq_GuestHeartbeat) %Rrc\n", rc));
    916 
    917                             if (RT_SUCCESS(rc))
    918                             {
    919                                 LogRel(("VBoxGuestInitDevExt: Setting up heartbeat to trigger every %RU64 sec\n",
    920                                         pDevExt->cNsHeartbeatInterval / 1000000000));
    921                                 rc = RTTimerCreateEx(&pDevExt->pHeartbeatTimer, pDevExt->cNsHeartbeatInterval,
    922                                                      0, (PFNRTTIMER)VBoxGuestHeartbeatTimerHandler, pDevExt);
    923                             }
    924 
    925                             if (RT_SUCCESS(rc))
    926                             {
    927                                 rc = RTTimerStart(pDevExt->pHeartbeatTimer, 0);
    928                                 if (RT_FAILURE(rc))
    929                                     LogRel(("VBoxGuestInitDevExt: Heartbeat timer failed to start, rc=%Rrc\n", rc));
    930                             }
    931                             if (RT_FAILURE(rc))
    932                             {
    933                                 LogRel(("VBoxGuestInitDevExt: Failed to set up the timer, guest heartbeat is disabled\n"));
    934                                 /* Disable host heartbeat check if we failed */
    935                                 VBoxGuestHeartbeatHostConfigure(pDevExt, false);
    936 
    937                                 VbglGRFree(pDevExt->pReqGuestHeartbeat);
    938                                 pDevExt->pReqGuestHeartbeat = NULL;
    939                             }
    940                         }
    941                         else
    942                             LogRel(("VBoxGuestInitDevExt: Failed to configure host for heartbeat checking, rc=%Rrc\n", rc));
     961                        vboxGuestInitFixateGuestMappings(pDevExt);
     962                        vbgdHeartbeatInit(pDevExt);
     963
     964                        rc = VBoxGuestReportDriverStatus(true /* Driver is active */);
     965                        if (RT_FAILURE(rc))
     966                            LogRel(("VBoxGuestInitDevExt: VBoxReportGuestDriverStatus failed, rc=%Rrc\n", rc));
     967
     968                        LogFlowFunc(("VBoxGuestInitDevExt: returns success\n"));
     969                        return VINF_SUCCESS;
    943970                    }
    944 
    945                     LogFlowFunc(("VBoxGuestInitDevExt: returns success\n"));
    946                     return VINF_SUCCESS;
    947971                }
    948972
     
    10901114    RTSpinlockAcquire(pDevExt->SessionSpinlock);
    10911115    RTListAppend(&pDevExt->SessionList, &pSession->ListNode);
     1116    pDevExt->cSessions++;
    10921117    RTSpinlockRelease(pDevExt->SessionSpinlock);
    10931118
     
    11231148    RTSpinlockAcquire(pDevExt->SessionSpinlock);
    11241149    RTListAppend(&pDevExt->SessionList, &pSession->ListNode);
     1150    pDevExt->cSessions++;
    11251151    RTSpinlockRelease(pDevExt->SessionSpinlock);
    11261152
     
    11481174    RTSpinlockAcquire(pDevExt->SessionSpinlock);
    11491175    RTListNodeRemove(&pSession->ListNode);
     1176    pDevExt->cSessions--;
    11501177    RTSpinlockRelease(pDevExt->SessionSpinlock);
    1151     VBoxGuestCommonGuestCapsAcquire(pDevExt, pSession, 0, UINT32_MAX, VBOXGUESTCAPSACQUIRE_FLAGS_NONE);
     1178    vbgdAcquireSessionCapabilities(pDevExt, pSession, 0, UINT32_MAX, VBOXGUESTCAPSACQUIRE_FLAGS_NONE,
     1179                                   true /*fSessionTermination*/);
     1180    vbgdSetSessionCapabilities(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/);
    11521181
    11531182    VBoxGuestCommonIOCtl_CancelAllWaitEvents(pDevExt, pSession);
     
    11711200    vboxGuestCloseMemBalloon(pDevExt, pSession);
    11721201    RTMemFree(pSession);
     1202
    11731203    /* Update the host flags (mouse status etc) not to reflect this session. */
    11741204    vboxGuestUpdateHostFlags(pDevExt, NULL,
     
    14361466                                        int iEvent, const uint32_t fReqEvents)
    14371467{
    1438     uint32_t fMatches = VBoxGuestCommonGetAndCleanPendingEventsLocked(pDevExt, pSession, fReqEvents);
     1468    uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents;
     1469    if (fMatches & VBOXGUEST_ACQUIRE_STYLE_EVENTS)
     1470        fMatches &= vbgdGetAllowedEventMaskForSession(pDevExt, pSession);
    14391471    if (fMatches || pSession->fPendingCancelWaitEvents)
    14401472    {
     1473        ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches);
    14411474        RTSpinlockRelease(pDevExt->EventSpinlock);
    14421475
     
    16591692        case VMMDevReq_HGCMCancel2:
    16601693#endif /* VBOX_WITH_HGCM */
     1694        case VMMDevReq_SetGuestCapabilities:
    16611695        default:
    16621696            enmRequired = kLevel_NoOne;
     
    16971731            break;
    16981732
    1699         /*
    1700          * Anyone. But not for CapsAcquire mode
    1701          */
    1702         case VMMDevReq_SetGuestCapabilities:
    1703         {
    1704             VMMDevReqGuestCapabilities2 *pCaps = (VMMDevReqGuestCapabilities2*)pReqHdr;
    1705             uint32_t fAcquireCaps = 0;
    1706             if (!VBoxGuestCommonGuestCapsModeSet(pDevExt, pCaps->u32OrMask, false, &fAcquireCaps))
    1707             {
    1708                 AssertFailed();
    1709                 LogRel(("VBoxDrv: calling caps set for acquired caps %d\n", pCaps->u32OrMask));
    1710                 enmRequired = kLevel_NoOne;
    1711                 break;
    1712             }
    1713             /* hack to adjust the notcaps.
    1714              * @todo: move to a better place
    1715              * user-mode apps are allowed to pass any mask to the notmask,
    1716              * the driver cleans up them accordingly */
    1717             pCaps->u32NotMask &= ~fAcquireCaps;
    1718             /* do not break, make it fall through to the below enmRequired setting */
    1719         }
    17201733        /*
    17211734         * Anyone.
     
    24092422 */
    24102423
    2411 static bool VBoxGuestCommonGuestCapsValidateValues(uint32_t fCaps)
    2412 {
    2413     if (fCaps & ~(  VMMDEV_GUEST_SUPPORTS_SEAMLESS
    2414                   | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING
    2415                   | VMMDEV_GUEST_SUPPORTS_GRAPHICS ))
    2416         return false;
    2417     return true;
    2418 }
    2419 
    2420 
    2421 /** Check whether any unreported VMM device events should be reported to any of
    2422  * the currently listening sessions.  In addition, report any events in
    2423  * @a fGenFakeEvents.
    2424  *
    2425  * @note This is called by GUEST_CAPS_ACQUIRE in case any pending events can now
    2426  *       be dispatched to the session which acquired capabilities.  The fake
    2427  *       events are a hack to wake up threads in that session which would not
    2428  *       otherwise be woken.
    2429  * @todo Why not just use CANCEL_ALL_WAITEVENTS to do the waking up rather than
    2430  *       adding additional code to the driver?
    2431  * @todo Why does acquiring capabilities block and unblock events?  Capabilities
    2432  *       are supposed to control what is reported to the host, we already have
    2433  *       separate requests for blocking and unblocking events.
    2434  */
    2435 static void VBoxGuestCommonCheckEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fGenFakeEvents)
    2436 {
    2437     RTSpinlockAcquire(pDevExt->EventSpinlock);
    2438     uint32_t fEvents = fGenFakeEvents | pDevExt->f32PendingEvents;
    2439     PVBOXGUESTWAIT  pWait;
    2440     PVBOXGUESTWAIT  pSafe;
    2441 
    2442     RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
    2443     {
    2444         uint32_t fHandledEvents = VBoxGuestCommonGetHandledEventsLocked(pDevExt, pWait->pSession);
    2445         if (    (pWait->fReqEvents & fEvents & fHandledEvents)
    2446                     &&  !pWait->fResEvents)
    2447         {
    2448             pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents;
    2449             Assert(!(fGenFakeEvents & pWait->fResEvents) || pSession == pWait->pSession);
    2450             fEvents &= ~pWait->fResEvents;
    2451             RTListNodeRemove(&pWait->ListNode);
    2452 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
    2453             RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
    2454 #else
    2455             RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
    2456             int rc = RTSemEventMultiSignal(pWait->Event);
    2457             AssertRC(rc);
    2458 #endif
    2459             if (!fEvents)
    2460                 break;
    2461         }
    2462     }
    2463     ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents);
    2464 
    2465     RTSpinlockRelease(pDevExt->EventSpinlock);
    2466 
    2467 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
    2468     VBoxGuestWaitDoWakeUps(pDevExt);
    2469 #endif
    2470 }
    2471 
    2472 
    2473 /** Return the mask of VMM device events that this session is allowed to see,
    2474  *  ergo, all events except those in "acquire" mode which have not been acquired
    2475  *  by this session. */
    2476 static uint32_t VBoxGuestCommonGetHandledEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
    2477 {
    2478     if (!pDevExt->u32AcquireModeGuestCaps)
    2479         return VMMDEV_EVENT_VALID_EVENT_MASK;
    2480 
    2481     /** @note VMMDEV_EVENT_VALID_EVENT_MASK should actually be the mask of valid
    2482      *        capabilities, but that doesn't affect this code. */
    2483     uint32_t u32AllowedGuestCaps = pSession->u32AquiredGuestCaps | (VMMDEV_EVENT_VALID_EVENT_MASK & ~pDevExt->u32AcquireModeGuestCaps);
    2484     uint32_t u32CleanupEvents = VBOXGUEST_ACQUIRE_STYLE_EVENTS;
    2485     if (u32AllowedGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS)
    2486         u32CleanupEvents &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
    2487     if (u32AllowedGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
    2488         u32CleanupEvents &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
    2489 
    2490     return VMMDEV_EVENT_VALID_EVENT_MASK & ~u32CleanupEvents;
    2491 }
    2492 
    2493 
    2494 static uint32_t VBoxGuestCommonGetAndCleanPendingEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fReqEvents)
    2495 {
    2496     uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents & VBoxGuestCommonGetHandledEventsLocked(pDevExt, pSession);
    2497     if (fMatches)
    2498         ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches);
    2499     return fMatches;
    2500 }
    2501 
    2502 
    2503 /** Puts a capability in "acquire" or "set" mode and returns the mask of
    2504  * capabilities currently in the other mode.  Once a capability has been put in
    2505  * one of the two modes it can no longer be removed from that mode. */
    2506 static bool VBoxGuestCommonGuestCapsModeSet(PVBOXGUESTDEVEXT pDevExt, uint32_t fCaps, bool fAcquire, uint32_t *pu32OtherVal)
    2507 {
    2508     uint32_t *pVal = fAcquire ? &pDevExt->u32AcquireModeGuestCaps : &pDevExt->u32SetModeGuestCaps;
    2509     const uint32_t fNotVal = !fAcquire ? pDevExt->u32AcquireModeGuestCaps : pDevExt->u32SetModeGuestCaps;
    2510     bool fResult = true;
    2511     RTSpinlockAcquire(pDevExt->EventSpinlock);
    2512 
    2513     if (!(fNotVal & fCaps))
    2514         *pVal |= fCaps;
    2515     else
    2516     {
    2517         AssertMsgFailed(("trying to change caps mode\n"));
    2518         fResult = false;
    2519     }
    2520 
    2521     RTSpinlockRelease(pDevExt->EventSpinlock);
    2522 
    2523     if (pu32OtherVal)
    2524         *pu32OtherVal = fNotVal;
    2525     return fResult;
    2526 }
    2527 
    2528 
    25292424/**
    25302425 * Sets the interrupt filter mask during initialization and termination.
     
    25452440    if (RT_FAILURE(rc))
    25462441        LogRel(("vboxGuestSetFilterMask: failed with rc=%Rrc\n", rc));
    2547     return rc;
    2548 }
    2549 
    2550 
    2551 /**
    2552  * Sets the guest capabilities to the host.
    2553  *
    2554  * This will ASSUME that we're the ones in charge of the mask, so
    2555  * we'll simply clear all bits we don't set.
    2556  *
    2557  * @returns VBox status code.
    2558  * @param   fMask       The new mask.
    2559  */
    2560 static int vboxGuestSetCapabilities(VMMDevReqGuestCapabilities2 *pReq, uint32_t fMask)
    2561 {
    2562     int rc;
    2563 
    2564     pReq->u32OrMask = fMask;
    2565     pReq->u32NotMask = ~fMask;
    2566     rc = VbglGRPerform(&pReq->header);
    2567     if (RT_FAILURE(rc))
    2568         LogRelFunc(("failed with rc=%Rrc\n", rc));
    25692442    return rc;
    25702443}
     
    25952468
    25962469static int vboxGuestGetHostFlagsFromSessions(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
    2597                                              uint32_t *pfFilterMask, uint32_t *pfCapabilities, uint32_t *pfMouseStatus)
     2470                                             uint32_t *pfFilterMask, uint32_t *pfMouseStatus)
    25982471{
    25992472    PVBOXGUESTSESSION pIterator;
    2600     uint32_t fFilterMask = 0, fCapabilities = 0, fMouseStatus = 0;
     2473    uint32_t fFilterMask = 0;
     2474    uint32_t fMouseStatus = 0;
    26012475    unsigned cSessions = 0;
    26022476    int rc = VINF_SUCCESS;
     
    26072481    {
    26082482        fFilterMask   |= pIterator->fFilterMask;
    2609         fCapabilities |= pIterator->fCapabilities;
    26102483        fMouseStatus  |= pIterator->fMouseStatus;
    26112484        ++cSessions;
    26122485    }
    26132486    if (!cSessions)
    2614         if (fFilterMask | fCapabilities | fMouseStatus)
     2487        if (fFilterMask | fMouseStatus)
    26152488            rc = VERR_INTERNAL_ERROR;
    26162489    if (cSessions == 1 && pSession)
    26172490        if (   fFilterMask   != pSession->fFilterMask
    2618             || fCapabilities != pSession->fCapabilities
    26192491            || fMouseStatus  != pSession->fMouseStatus)
    26202492            rc = VERR_INTERNAL_ERROR;
    26212493    if (cSessions > 1 && pSession)
    26222494        if (   ~fFilterMask   & pSession->fFilterMask
    2623             || ~fCapabilities & pSession->fCapabilities
    26242495            || ~fMouseStatus  & pSession->fMouseStatus)
    26252496            rc = VERR_INTERNAL_ERROR;
    26262497    *pfFilterMask = fFilterMask;
    2627     *pfCapabilities = fCapabilities;
    26282498    *pfMouseStatus = fMouseStatus;
    26292499    return rc;
     
    26452515    int rc;
    26462516    VMMDevCtlGuestFilterMask    *pFilterReq = NULL;
    2647     VMMDevReqGuestCapabilities2 *pCapabilitiesReq = NULL;
    26482517    VMMDevReqMouseStatus        *pStatusReq = NULL;
    26492518    uint32_t                     fFilterMask = 0;
    2650     uint32_t                     fCapabilities = 0;
    26512519    uint32_t                     fMouseStatus = 0;
    26522520
    26532521    rc = VbglGRAlloc((VMMDevRequestHeader **)&pFilterReq, sizeof(*pFilterReq),
    26542522                     VMMDevReq_CtlGuestFilterMask);
    2655     if (RT_SUCCESS(rc))
    2656         rc = VbglGRAlloc((VMMDevRequestHeader **)&pCapabilitiesReq,
    2657                          sizeof(*pCapabilitiesReq),
    2658                          VMMDevReq_SetGuestCapabilities);
    26592523    if (RT_SUCCESS(rc))
    26602524        rc = VbglGRAlloc((VMMDevRequestHeader **)&pStatusReq,
     
    26632527    {
    26642528        RTSpinlockAcquire(pDevExt->SessionSpinlock);
    2665         rc = vboxGuestGetHostFlagsFromSessions(pDevExt, pSession, &fFilterMask,
    2666                                                &fCapabilities, &fMouseStatus);
     2529        rc = vboxGuestGetHostFlagsFromSessions(pDevExt, pSession, &fFilterMask, &fMouseStatus);
    26672530        if (RT_SUCCESS(rc))
    26682531        {
     
    26732536            if (fFlags & HostFlags_FilterMask)
    26742537                vboxGuestSetFilterMask(pFilterReq, fFilterMask);
    2675             fCapabilities |= pDevExt->u32GuestCaps;
    2676             if (fFlags & HostFlags_Capabilities)
    2677                 vboxGuestSetCapabilities(pCapabilitiesReq, fCapabilities);
    26782538            if (fFlags & HostFlags_MouseStatus)
    26792539                vboxGuestSetMouseStatus(pStatusReq, fMouseStatus);
     
    26832543    if (pFilterReq)
    26842544        VbglGRFree(&pFilterReq->header);
    2685     if (pCapabilitiesReq)
    2686         VbglGRFree(&pCapabilitiesReq->header);
    26872545    if (pStatusReq)
    26882546        VbglGRFree(&pStatusReq->header);
     2547
    26892548    return rc;
    26902549}
    26912550
    2692 /** Switch the capabilities in @a fOrMask to "acquire" mode if they are not
    2693  * already in "set" mode.  If @a enmFlags is not set to
    2694  * VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE, also try to acquire those
    2695  * capabilities for the current session and release those in @a fNotFlag. */
    2696 static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
    2697                                            uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags)
    2698 {
    2699     uint32_t fSetCaps = 0;
    2700 
    2701     if (!VBoxGuestCommonGuestCapsValidateValues(fOrMask))
    2702     {
    2703         LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid fOrMask\n",
     2551
     2552/**
     2553 * Return the mask of VMM device events that this session is allowed to see.
     2554 *
     2555 * The events associated with guest capabilities in "acquire" mode will be
     2556 * restricted to sessions which has acquired the respective capabilities.
     2557 * If someone else tries to wait for acquired events, they won't be woken up
     2558 * when the event becomes pending.  Should some other thread in the session
     2559 * acquire the capability while the corresponding event is pending, the waiting
     2560 * thread will woken up.
     2561 *
     2562 * @returns Mask of events valid for the given session.
     2563 * @param   pDevExt             The device extension.
     2564 * @param   pSession            The session.
     2565 *
     2566 * @remarks Needs only be called when dispatching events in the
     2567 *          VBOXGUEST_ACQUIRE_STYLE_EVENTS mask.
     2568 */
     2569static uint32_t vbgdGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
     2570{
     2571    uint32_t fAcquireModeGuestCaps;
     2572    uint32_t fAcquiredGuestCaps;
     2573    uint32_t fAllowedEvents;
     2574
     2575    /*
     2576     * Note! Reads pSession->u32AquiredGuestCaps and pDevExt->u32AcquireModeGuestCaps
     2577     *       WITHOUT holding VBOXGUESTDEVEXT::SessionSpinlock.
     2578     */
     2579    fAcquireModeGuestCaps = ASMAtomicUoReadU32(&pDevExt->u32AcquireModeGuestCaps);
     2580    if (fAcquireModeGuestCaps == 0)
     2581        return VMMDEV_EVENT_VALID_EVENT_MASK;
     2582    fAcquiredGuestCaps = ASMAtomicUoReadU32(&pSession->u32AquiredGuestCaps);
     2583
     2584    /*
     2585     * Calculate which events to allow according to the cap config and caps
     2586     * acquired by the session.
     2587     */
     2588    fAllowedEvents = VMMDEV_EVENT_VALID_EVENT_MASK;
     2589    if (   !(fAcquiredGuestCaps   & VMMDEV_GUEST_SUPPORTS_GRAPHICS)
     2590        && (fAcquireModeGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS))
     2591        fAllowedEvents &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
     2592
     2593    if (   !(fAcquiredGuestCaps   & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
     2594        && (fAcquireModeGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS))
     2595        fAllowedEvents &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
     2596
     2597    return fAllowedEvents;
     2598}
     2599
     2600
     2601/**
     2602 * Sets the guest capabilities to the host while holding the lock.
     2603 *
     2604 * This will ASSUME that we're the ones in charge of the mask, so
     2605 * we'll simply clear all bits we don't set.
     2606 *
     2607 * @returns VBox status code.
     2608 * @param   fMask       The new mask.
     2609 */
     2610static int vbgdUpdateCapabilitiesOnHostWithReqAndLock(PVBOXGUESTDEVEXT pDevExt, VMMDevReqGuestCapabilities2 *pReq)
     2611{
     2612    int rc;
     2613    uint32_t iBit;
     2614
     2615    pReq->u32OrMask = pDevExt->u32GuestCapsAcquired;
     2616    for (iBit = 0; iBit < 32; iBit++)
     2617        if (pDevExt->acGuestCapsSet[iBit] > 0)
     2618            pReq->u32OrMask |= RT_BIT_32(iBit);
     2619
     2620    if (pReq->u32OrMask == pDevExt->fGuestCapsHost)
     2621        rc = VINF_SUCCESS;
     2622    else
     2623    {
     2624        pDevExt->fGuestCapsHost = pReq->u32OrMask;
     2625        pReq->u32NotMask = ~pReq->u32OrMask;
     2626        rc = VbglGRPerform(&pReq->header);
     2627        if (RT_FAILURE(rc))
     2628            pDevExt->fGuestCapsHost = UINT32_MAX;
     2629    }
     2630
     2631    return rc;
     2632}
     2633
     2634
     2635/**
     2636 * Sets the guest capabilities to the host.
     2637 *
     2638 * This will ASSUME that we're the ones in charge of the mask, so
     2639 * we'll simply clear all bits we don't set.
     2640 *
     2641 * @returns VBox status code.
     2642 * @param   fMask       The new mask.
     2643 */
     2644static int vbgdUpdateCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt)
     2645{
     2646    VMMDevReqGuestCapabilities2 *pReq;
     2647    int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
     2648    if (RT_SUCCESS(rc))
     2649    {
     2650        RTSpinlockAcquire(pDevExt->SessionSpinlock);
     2651
     2652        rc = vbgdUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
     2653
     2654        RTSpinlockRelease(pDevExt->SessionSpinlock);
     2655
     2656        if (RT_FAILURE(rc))
     2657            LogRelFunc(("failed with rc=%Rrc\n", rc));
     2658        VbglGRFree(&pReq->header);
     2659    }
     2660    return rc;
     2661}
     2662
     2663
     2664/**
     2665 * Switch a set of capabilities into "acuquire" mode and (maybe) acquire them
     2666 * for the given session.
     2667 *
     2668 * This is called in response to VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE as well as
     2669 * to do session cleanup.
     2670 *
     2671 * @returns VBox status code.
     2672 * @param   pDevExt             The device extension.
     2673 * @param   pSession            The session.
     2674 * @param   fOrMask             The capabilities to add .
     2675 * @param   fNotMask            The capabilities to remove.  Ignored in
     2676 *                              VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE.
     2677 * @param   enmFlags            Confusing operation modifier.
     2678 *                              VBOXGUESTCAPSACQUIRE_FLAGS_NONE means to both
     2679 *                              configure and acquire/release the capabilities.
     2680 *                              VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
     2681 *                              means only configure capabilities in the
     2682 *                              @a fOrMask capabilities for "acquire" mode.
     2683 * @param   fSessionTermination Set if we're called by the session cleanup code.
     2684 *                              This tweaks the error handling so we perform
     2685 *                              proper session cleanup even if the host
     2686 *                              misbehaves.
     2687 *
     2688 * @remarks Takes both the session and event spinlocks.
     2689 */
     2690static int vbgdAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
     2691                                          uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags,
     2692                                          bool fSessionTermination)
     2693{
     2694    uint32_t fCurrentOwnedCaps;
     2695    uint32_t fSessionRemovedCaps;
     2696    uint32_t fSessionAddedCaps;
     2697    uint32_t fOtherConflictingCaps;
     2698    VMMDevReqGuestCapabilities2 *pReq = NULL;
     2699    int rc;
     2700
     2701
     2702    /*
     2703     * Validate and adjust input.
     2704     */
     2705    if (fOrMask & ~(  VMMDEV_GUEST_SUPPORTS_SEAMLESS
     2706                    | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING
     2707                    | VMMDEV_GUEST_SUPPORTS_GRAPHICS ) )
     2708    {
     2709        LogRel(("vbgdAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x -- invalid fOrMask\n",
    27042710                pSession, fOrMask, fNotMask, enmFlags));
    27052711        return VERR_INVALID_PARAMETER;
     
    27092715        && enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_NONE)
    27102716    {
    2711         LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid enmFlags %d\n",
     2717        LogRel(("vbgdAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: invalid enmFlags %d\n",
    27122718                pSession, fOrMask, fNotMask, enmFlags));
    27132719        return VERR_INVALID_PARAMETER;
    27142720    }
    27152721
    2716     if (!VBoxGuestCommonGuestCapsModeSet(pDevExt, fOrMask, true, &fSetCaps))
    2717     {
    2718         LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- calling caps acquire for set caps\n",
     2722    /* The fNotMask no need to have all values valid, invalid ones will simply be ignored. */
     2723    fNotMask &= ~fOrMask;
     2724
     2725    /*
     2726     * Preallocate a update request if we're about to do more than just configure
     2727     * the capability mode.
     2728     */
     2729    if (enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE)
     2730    {
     2731        rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
     2732        if (RT_FAILURE(rc))
     2733        {
     2734            LogRel(("vbgdAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: VbglGRAlloc failure: %Rrc\n",
     2735                    pSession, fOrMask, fNotMask, enmFlags, rc));
     2736            return rc;
     2737        }
     2738    }
     2739
     2740    /*
     2741     * Try switch the capabilities in the OR mask into "acquire" mode.
     2742     *
     2743     * Note! We currently ignore anyone which may already have "set" the capabilities
     2744     *       in fOrMask.  This is simple, but perhaps not the best idea?
     2745     */
     2746    RTSpinlockAcquire(pDevExt->EventSpinlock);
     2747
     2748    if (!(pDevExt->u32SetModeGuestCaps & fOrMask))
     2749        pDevExt->u32AcquireModeGuestCaps |= fOrMask;
     2750    else
     2751    {
     2752        RTSpinlockRelease(pDevExt->EventSpinlock);
     2753
     2754        if (pReq)
     2755            VbglGRFree(&pReq->header);
     2756        AssertMsgFailed(("Trying to change caps mode: %#x\n", fOrMask));
     2757        LogRel(("vbgdAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: calling caps acquire for set caps\n",
    27192758                pSession, fOrMask, fNotMask, enmFlags));
    27202759        return VERR_INVALID_STATE;
    27212760    }
    27222761
     2762    /*
     2763     * If we only wanted to switch the capabilities into "acquire" mode, we're done now.
     2764     */
    27232765    if (enmFlags & VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE)
    27242766    {
    2725         Log(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- configured acquire caps: 0x%x\n",
     2767        RTSpinlockRelease(pDevExt->EventSpinlock);
     2768
     2769        Assert(!pReq);
     2770        Log(("vbgdAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: configured acquire caps: 0x%x\n",
    27262771             pSession, fOrMask, fNotMask, enmFlags));
    27272772        return VINF_SUCCESS;
    27282773    }
    2729 
    2730     /* the fNotMask no need to have all values valid,
    2731      * invalid ones will simply be ignored */
    2732     uint32_t fCurrentOwnedCaps;
    2733     uint32_t fSessionNotCaps;
    2734     uint32_t fSessionOrCaps;
    2735     uint32_t fOtherConflictingCaps;
    2736 
    2737     fNotMask &= ~fOrMask;
    2738 
    2739     RTSpinlockAcquire(pDevExt->EventSpinlock);
    2740 
     2774    Assert(pReq);
     2775
     2776    /*
     2777     * Caller wants to acquire/release the capabilities too.
     2778     *
     2779     * Note! The mode change of the capabilities above won't be reverted on
     2780     *       failure, this is intentional.
     2781     */
    27412782    fCurrentOwnedCaps      = pSession->u32AquiredGuestCaps;
    2742     fSessionNotCaps        = fCurrentOwnedCaps & fNotMask;
    2743     fSessionOrCaps         = fOrMask & ~fCurrentOwnedCaps;
    2744     fOtherConflictingCaps  = pDevExt->u32GuestCaps & ~fCurrentOwnedCaps;
    2745     fOtherConflictingCaps &= fSessionOrCaps;
     2783    fSessionRemovedCaps    = fCurrentOwnedCaps & fNotMask;
     2784    fSessionAddedCaps      = fOrMask & ~fCurrentOwnedCaps;
     2785    fOtherConflictingCaps  = pDevExt->u32GuestCapsAcquired & ~fCurrentOwnedCaps;
     2786    fOtherConflictingCaps &= fSessionAddedCaps;
    27462787
    27472788    if (!fOtherConflictingCaps)
    27482789    {
    2749         if (fSessionOrCaps)
    2750         {
    2751             pSession->u32AquiredGuestCaps |= fSessionOrCaps;
    2752             pDevExt->u32GuestCaps |= fSessionOrCaps;
    2753         }
    2754 
    2755         if (fSessionNotCaps)
    2756         {
    2757             pSession->u32AquiredGuestCaps &= ~fSessionNotCaps;
    2758             pDevExt->u32GuestCaps &= ~fSessionNotCaps;
    2759         }
     2790        if (fSessionAddedCaps)
     2791        {
     2792            pSession->u32AquiredGuestCaps |= fSessionAddedCaps;
     2793            pDevExt->u32GuestCapsAcquired |= fSessionAddedCaps;
     2794        }
     2795
     2796        if (fSessionRemovedCaps)
     2797        {
     2798            pSession->u32AquiredGuestCaps &= ~fSessionRemovedCaps;
     2799            pDevExt->u32GuestCapsAcquired &= ~fSessionRemovedCaps;
     2800        }
     2801
     2802        /*
     2803         * If something changes (which is very likely), tell the host.
     2804         */
     2805        if (fSessionAddedCaps || fSessionRemovedCaps)
     2806        {
     2807            rc = vbgdUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
     2808            if (RT_FAILURE(rc))
     2809            {
     2810                /*
     2811                 * Failed, roll back.  Except, don't roll back session cleanups.
     2812                 */
     2813                if (fSessionAddedCaps)
     2814                {
     2815                    pSession->u32AquiredGuestCaps &= ~fSessionAddedCaps;
     2816                    pDevExt->u32GuestCapsAcquired &= ~fSessionAddedCaps;
     2817                }
     2818                if (fSessionRemovedCaps && !fSessionTermination)
     2819                {
     2820                    pSession->u32AquiredGuestCaps |= fSessionRemovedCaps;
     2821                    pDevExt->u32GuestCapsAcquired |= fSessionRemovedCaps;
     2822                }
     2823
     2824                RTSpinlockRelease(pDevExt->EventSpinlock);
     2825                LogRel(("vbgdAcquireSessionCapabilities: VBoxGuestSetGuestCapabilities failed: rc=%Rrc\n", rc));
     2826                VbglGRFree(&pReq->header);
     2827                return rc;
     2828            }
     2829        }
     2830
     2831    }
     2832    else
     2833    {
     2834        RTSpinlockRelease(pDevExt->EventSpinlock);
     2835
     2836        Log(("vbgdAcquireSessionCapabilities: Caps %#x were busy\n", fOtherConflictingCaps));
     2837        VbglGRFree(&pReq->header);
     2838        return VERR_RESOURCE_BUSY;
    27602839    }
    27612840
    27622841    RTSpinlockRelease(pDevExt->EventSpinlock);
    2763 
    2764     if (fOtherConflictingCaps)
    2765     {
    2766         Log(("VBoxGuestCommonGuestCapsAcquire: Caps 0x%x were busy\n", fOtherConflictingCaps));
    2767         return VERR_RESOURCE_BUSY;
    2768     }
    2769 
    2770     /* now do host notification outside the lock */
    2771     if (!fSessionOrCaps && !fSessionNotCaps)
    2772     {
    2773         /* no changes, return */
    2774         return VINF_SUCCESS;
    2775     }
    2776 
    2777     int rc = VBoxGuestSetGuestCapabilities(fSessionOrCaps, fSessionNotCaps);
    2778     if (RT_FAILURE(rc))
    2779     {
    2780         LogRel(("VBoxGuestCommonGuestCapsAcquire: VBoxGuestSetGuestCapabilities failed, rc=%Rrc\n", rc));
    2781 
    2782         /* Failure branch
    2783          * this is generally bad since e.g. failure to release the caps may result in other sessions not being able to use it
    2784          * so we are not trying to restore the caps back to their values before the VBoxGuestCommonGuestCapsAcquire call,
    2785          * but just pretend everithing is OK. */
    2786         /** @todo better failure handling mechanism? */
    2787     }
    2788 
    2789     /* success! */
    2790     uint32_t fGenFakeEvents = 0;
    2791 
    2792     if (fSessionOrCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
    2793     {
    2794         /* generate the seamless change event so that the r3 app could synch with the seamless state
    2795          * although this introduces a false alarming of r3 client, it still solve the problem of
    2796          * client state inconsistency in multiuser environment */
    2797         fGenFakeEvents |= VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
    2798     }
    2799 
    2800     /* since the acquire filter mask has changed, we need to process events in any way to ensure they go from pending events field
    2801      * to the proper (un-filtered) entries */
    2802     VBoxGuestCommonCheckEvents(pDevExt, pSession, fGenFakeEvents);
     2842    VbglGRFree(&pReq->header);
     2843
     2844    /*
     2845     * If we added a capability, check if that means some other thread in our
     2846     * session should be unblocked because there are events pending.
     2847     *
     2848     * HACK ALERT! When the seamless support capability is added we generate a
     2849     *             seamless change event so that the ring-3 client can sync with
     2850     *             the seamless state. Although this introduces a spurious
     2851     *             wakeups of the ring-3 client, it solves the problem of client
     2852     *             state inconsistency in multiuser environment (on Windows).
     2853     */
     2854    if (fSessionAddedCaps)
     2855    {
     2856        uint32_t fGenFakeEvents = 0;
     2857        if (fSessionAddedCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
     2858            fGenFakeEvents |= VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
     2859
     2860        RTSpinlockAcquire(pDevExt->EventSpinlock);
     2861        if (fGenFakeEvents || pDevExt->f32PendingEvents)
     2862            vbgdDispatchEventsLocked(pDevExt, fGenFakeEvents);
     2863        RTSpinlockRelease(pDevExt->EventSpinlock);
     2864
     2865#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
     2866        VBoxGuestWaitDoWakeUps(pDevExt);
     2867#endif
     2868    }
    28032869
    28042870    return VINF_SUCCESS;
     
    28062872
    28072873
     2874/**
     2875 * Handle VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE.
     2876 *
     2877 * @returns VBox status code.
     2878 *
     2879 * @param   pDevExt             The device extension.
     2880 * @param   pSession            The session.
     2881 * @param   pAcquire            The request.
     2882 */
    28082883static int VBoxGuestCommonIOCTL_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
    28092884                                                 VBoxGuestCapsAquire *pAcquire)
    28102885{
    2811     int rc = VBoxGuestCommonGuestCapsAcquire(pDevExt, pSession, pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags);
     2886    int rc;
     2887    LogFlow(("VBoxGuestCommonIOCtl: GUEST_CAPS_ACQUIRE or=%#x not=%#x flags=%#x\n",
     2888             pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags));
     2889
     2890    rc = vbgdAcquireSessionCapabilities(pDevExt, pSession, pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags,
     2891                                        false /*fSessionTermination*/);
    28122892    if (RT_FAILURE(rc))
    28132893        LogRel(("VBoxGuestCommonIOCtl: GUEST_CAPS_ACQUIRE failed rc=%Rrc\n", rc));
     
    28172897
    28182898
     2899/**
     2900 * Sets the guest capabilities for a session.
     2901 *
     2902 * @returns VBox status code.
     2903 * @param   pDevExt             The device extension.
     2904 * @param   pSession            The session.
     2905 * @param   fOrMask             The capabilities to add.
     2906 * @param   fNotMask            The capabilities to remove.
     2907 *
     2908 * @remarks Takes the session spinlock.
     2909 */
     2910static int vbgdSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask)
     2911{
     2912    int rc;
     2913    RTSpinlockAcquire(pDevExt->SessionSpinlock);
     2914
     2915#ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
     2916    /*
     2917     * Capabilities in "acquire" mode cannot be set via this API.
     2918     * (Acquire mode is only used on windows at the time of writing.)
     2919     */
     2920    if (!(fOrMask & pDevExt->u32AcquireModeGuestCaps))
     2921#endif
     2922    {
     2923        /*
     2924         * Apply the changes to the session mask.
     2925         */
     2926        uint32_t fChanged;
     2927        uint32_t fPrevious = pSession->fCapabilities;
     2928        pSession->fCapabilities |= fOrMask;
     2929        pSession->fCapabilities &= ~fNotMask;
     2930
     2931        /*
     2932         * If anything actually changed, update the global usage counters.
     2933         */
     2934        fChanged = fPrevious ^ pSession->fCapabilities;
     2935        if (fChanged)
     2936        {
     2937            bool        fGlobalChange = false;
     2938            uint32_t    iBit;
     2939            for (iBit = ASMBitFirstSetU32(fChanged) - 1; iBit < 32; iBit++)
     2940                if (RT_BIT_32(iBit) & fChanged)
     2941                {
     2942                    if (fChanged & fPrevious)
     2943                    {
     2944                        pDevExt->acGuestCapsSet[iBit] -= 1;
     2945                        AssertMsg(pDevExt->acGuestCapsSet[iBit] <= pDevExt->cSessions,
     2946                                  ("pDevExt->acGuestCaps[%u]=%#x cSessions=%#x\n",
     2947                                   iBit, pDevExt->acGuestCapsSet[iBit], pDevExt->cSessions));
     2948                        fGlobalChange |= pDevExt->acGuestCapsSet[iBit] == 0;
     2949                    }
     2950                    else
     2951                    {
     2952                        pDevExt->acGuestCapsSet[iBit] += 1;
     2953                        AssertMsg(pDevExt->acGuestCapsSet[iBit] > 0 && pDevExt->acGuestCapsSet[iBit] <= pDevExt->cSessions,
     2954                                  ("pDevExt->acGuestCaps[%u]=%#x cSessions=%#x\n",
     2955                                   iBit, pDevExt->acGuestCapsSet[iBit], pDevExt->cSessions));
     2956                        fGlobalChange |= pDevExt->acGuestCapsSet[iBit] == 1;
     2957                    }
     2958                    fChanged &= ~RT_BIT_32(iBit);
     2959                    if (!fChanged)
     2960                        break;
     2961                }
     2962
     2963            /*
     2964             * If there were global changes, update the capabilities on the host.
     2965             */
     2966            if (fGlobalChange)
     2967            {
     2968                RTSpinlockRelease(pDevExt->SessionSpinlock);
     2969
     2970                return vbgdUpdateCapabilitiesOnHost(pDevExt);
     2971            }
     2972        }
     2973        rc = VINF_SUCCESS;
     2974    }
     2975#ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
     2976    else
     2977        rc = VERR_RESOURCE_BUSY;
     2978#endif
     2979
     2980    RTSpinlockRelease(pDevExt->SessionSpinlock);
     2981    return rc;
     2982}
     2983
     2984
     2985/**
     2986 * Handle VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES.
     2987 *
     2988 * @returns VBox status code.
     2989 *
     2990 * @param   pDevExt             The device extension.
     2991 * @param   pSession            The session.
     2992 * @param   pInfo               The request.
     2993 */
    28192994static int VBoxGuestCommonIOCtl_SetCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
    28202995                                                VBoxGuestSetCapabilitiesInfo *pInfo)
    28212996{
    28222997    int rc;
    2823 
    2824     if ((pInfo->u32OrMask | pInfo->u32NotMask) & ~VMMDEV_GUEST_CAPABILITIES_MASK)
    2825         return VERR_INVALID_PARAMETER;
    2826     RTSpinlockAcquire(pDevExt->SessionSpinlock);
    2827     pSession->fCapabilities |= pInfo->u32OrMask;
    2828     pSession->fCapabilities &= ~pInfo->u32NotMask;
    2829     RTSpinlockRelease(pDevExt->SessionSpinlock);
    2830     rc = vboxGuestUpdateHostFlags(pDevExt, pSession, HostFlags_Capabilities);
     2998    LogFlow(("VBoxGuestCommonIOCtl: SET_GUEST_CAPABILITIES or=%#x not=%#x\n", pInfo->u32OrMask, pInfo->u32NotMask));
     2999
     3000    if (!((pInfo->u32OrMask | pInfo->u32NotMask) & ~VMMDEV_GUEST_CAPABILITIES_MASK))
     3001        rc = vbgdSetSessionCapabilities(pDevExt, pSession, pInfo->u32OrMask, pInfo->u32NotMask);
     3002    else
     3003        rc = VERR_INVALID_PARAMETER;
     3004
    28313005    return rc;
    28323006}
     
    30773251
    30783252
     3253/**
     3254 * Used by VBoxGuestCommonISR as well as the acquire guest capability code.
     3255 *
     3256 * @returns VINF_SUCCESS on success. On failure, ORed together
     3257 *          RTSemEventMultiSignal errors (completes processing despite errors).
     3258 * @param   pDevExt             The VBoxGuest device extension.
     3259 * @param   fEvents             The events to dispatch.
     3260 */
     3261static int vbgdDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents)
     3262{
     3263    PVBOXGUESTWAIT  pWait;
     3264    PVBOXGUESTWAIT  pSafe;
     3265    int             rc = VINF_SUCCESS;
     3266
     3267    fEvents |= pDevExt->f32PendingEvents;
     3268
     3269    RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
     3270    {
     3271        uint32_t fHandledEvents = pWait->fReqEvents & fEvents;
     3272        if (    fHandledEvents != 0
     3273            &&  !pWait->fResEvents)
     3274        {
     3275            /* Does this one wait on any of the events we're dispatching?  We do a quick
     3276               check first, then deal with VBOXGUEST_ACQUIRE_STYLE_EVENTS as applicable. */
     3277            if (fHandledEvents & VBOXGUEST_ACQUIRE_STYLE_EVENTS)
     3278                fHandledEvents &= vbgdGetAllowedEventMaskForSession(pDevExt, pWait->pSession);
     3279            if (fHandledEvents)
     3280            {
     3281                pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents;
     3282                fEvents &= ~pWait->fResEvents;
     3283                RTListNodeRemove(&pWait->ListNode);
     3284#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
     3285                RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
     3286#else
     3287                RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
     3288                rc |= RTSemEventMultiSignal(pWait->Event);
     3289#endif
     3290                if (!fEvents)
     3291                    break;
     3292            }
     3293        }
     3294    }
     3295
     3296    ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents);
     3297    return rc;
     3298}
     3299
    30793300
    30803301/**
     
    31633384             * Normal FIFO waiter evaluation.
    31643385             */
    3165             fEvents |= pDevExt->f32PendingEvents;
    3166             RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
    3167             {
    3168                 uint32_t fHandledEvents = VBoxGuestCommonGetHandledEventsLocked(pDevExt, pWait->pSession);
    3169                 if (    (pWait->fReqEvents & fEvents & fHandledEvents)
    3170                     &&  !pWait->fResEvents)
    3171                 {
    3172                     pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents;
    3173                     fEvents &= ~pWait->fResEvents;
    3174                     RTListNodeRemove(&pWait->ListNode);
    3175 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
    3176                     RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
    3177 #else
    3178                     RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
    3179                     rc |= RTSemEventMultiSignal(pWait->Event);
    3180 #endif
    3181                     if (!fEvents)
    3182                         break;
    3183                 }
    3184             }
    3185             ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents);
     3386            rc |= vbgdDispatchEventsLocked(pDevExt, fEvents);
    31863387        }
    31873388        else /* something is serious wrong... */
  • trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h

    r54296 r54601  
    163163     * #SessionSpinlock lock. */
    164164    RTLISTANCHOR                SessionList;
     165    /** Number of session. */
     166    uint32_t                    cSessions;
    165167    /** Flag indicating whether logging to the release log
    166168     *  is enabled. */
     
    170172    /** Callback and user data for a kernel mouse handler. */
    171173    VBoxGuestMouseSetNotifyCallback MouseNotifyCallback;
     174
     175    /** @name Guest Capabilities.
     176     * @{ */
    172177    /** Guest capabilities which have been set to "acquire" mode.  This means
    173178     * that only one session can use them at a time, and that they will be
    174      * automatically cleaned up if that session exits without doing so. */
    175     uint32_t                    u32AcquireModeGuestCaps;
     179     * automatically cleaned up if that session exits without doing so.
     180     *
     181     * Protected by VBOXGUESTDEVEXT::SessionSpinlock, but is unfortunately read
     182     * without holding the lock in a couple of places. */
     183    uint32_t volatile           u32AcquireModeGuestCaps;
    176184    /** Guest capabilities which have been set to "set" mode.  This just means
    177185     * that they have been blocked from ever being set to "acquire" mode. */
     
    179187    /** Mask of all capabilities which are currently acquired by some session
    180188     * and as such reported to the host. */
    181     uint32_t                    u32GuestCaps;
     189    uint32_t                    u32GuestCapsAcquired;
     190    /** Usage counters for guest capabilities in "set" mode. Indexed by
     191     *  capability bit number, one count per session using a capability. */
     192    uint32_t                    acGuestCapsSet[32];
     193    /** The set guest capabilities reported to the host. */
     194    uint32_t                    fGuestCapsHost;
     195    /** @} */
     196
    182197    /** Heartbeat timer which fires with interval
    183198      * cNsHearbeatInterval and its handler sends
     
    230245     * Use under the VBOXGUESTDEVEXT#SessionSpinlock lock. */
    231246    uint32_t                    fFilterMask;
    232     /** Capabilities supported.  A capability enabled in any guest session will
    233      * be enabled for the host.
    234      * Use under the VBOXGUESTDEVEXT#SessionSpinlock lock. */
     247    /** Guest capabilities held in "acquired" by this session.
     248     * Protected by VBOXGUESTDEVEXT::SessionSpinlock, but is unfortunately read
     249     * without holding the lock in a couple of places. */
     250    uint32_t volatile           u32AquiredGuestCaps;
     251    /** Guest capabilities in "set" mode for this session.
     252     * These accumulated for sessions via VBOXGUESTDEVEXT::acGuestCapsSet and
     253     * reported to the host.  Protected by VBOXGUESTDEVEXT::SessionSpinlock.  */
    235254    uint32_t                    fCapabilities;
    236255    /** Mouse features supported.  A feature enabled in any guest session will
     
    249268    bool                        fOpened;
    250269#endif
    251     /** Mask of guest capabilities acquired by this session.  These will all be
    252      *  reported to the host. */
    253     uint32_t                    u32AquiredGuestCaps;
    254270    /** Whether a CANCEL_ALL_WAITEVENTS is pending.  This happens when
    255271     * CANCEL_ALL_WAITEVENTS is called, but no call to WAITEVENT is in process
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette