Changeset 54601 in vbox for trunk/src/VBox/Additions
- Timestamp:
- Mar 3, 2015 4:20:06 PM (10 years ago)
- Location:
- trunk/src/VBox/Additions/common/VBoxGuest
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
r54593 r54601 77 77 { 78 78 HostFlags_FilterMask = 1, 79 HostFlags_Capabilities = 2,80 79 HostFlags_MouseStatus = 4, 81 80 HostFlags_All = 7, … … 90 89 static DECLCALLBACK(int) VBoxGuestHGCMAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdrNonVolatile, void *pvUser, uint32_t u32User); 91 90 #endif 92 static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask,93 uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags);94 91 static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession); 95 92 static 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); 93 static uint32_t vbgdGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession); 94 static int vbgdUpdateCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt); 95 static int vbgdAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, 96 uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags, bool fSessionTermination); 97 static int vbgdSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNoMask); 98 static int vbgdDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents); 99 99 100 100 … … 552 552 553 553 /** 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 */ 561 static 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 /** 554 613 * Helper to reinit the VBoxVMM communication after hibernation. 555 614 * … … 808 867 RTListInit(&pDevExt->FreeList); 809 868 RTListInit(&pDevExt->SessionList); 869 pDevExt->cSessions = 0; 810 870 pDevExt->fLoggingEnabled = false; 811 871 pDevExt->f32PendingEvents = 0; … … 844 904 pDevExt->u32AcquireModeGuestCaps = 0; 845 905 pDevExt->u32SetModeGuestCaps = 0; 846 pDevExt->u32GuestCaps = 0; 906 pDevExt->u32GuestCapsAcquired = 0; 907 RT_ZERO(pDevExt->acGuestCapsSet); 908 pDevExt->fGuestCapsHost = UINT32_MAX; /* forces a report */ 847 909 848 910 /* … … 886 948 if (RT_SUCCESS(rc)) 887 949 { 888 /* Set the fixed event and disable the guest graphics capability 950 /* 951 * Set the fixed event and disable the guest graphics capability 889 952 * 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); 892 956 if (RT_SUCCESS(rc)) 893 957 { 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); 903 959 if (RT_SUCCESS(rc)) 904 960 { 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; 943 970 } 944 945 LogFlowFunc(("VBoxGuestInitDevExt: returns success\n"));946 return VINF_SUCCESS;947 971 } 948 972 … … 1090 1114 RTSpinlockAcquire(pDevExt->SessionSpinlock); 1091 1115 RTListAppend(&pDevExt->SessionList, &pSession->ListNode); 1116 pDevExt->cSessions++; 1092 1117 RTSpinlockRelease(pDevExt->SessionSpinlock); 1093 1118 … … 1123 1148 RTSpinlockAcquire(pDevExt->SessionSpinlock); 1124 1149 RTListAppend(&pDevExt->SessionList, &pSession->ListNode); 1150 pDevExt->cSessions++; 1125 1151 RTSpinlockRelease(pDevExt->SessionSpinlock); 1126 1152 … … 1148 1174 RTSpinlockAcquire(pDevExt->SessionSpinlock); 1149 1175 RTListNodeRemove(&pSession->ListNode); 1176 pDevExt->cSessions--; 1150 1177 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*/); 1152 1181 1153 1182 VBoxGuestCommonIOCtl_CancelAllWaitEvents(pDevExt, pSession); … … 1171 1200 vboxGuestCloseMemBalloon(pDevExt, pSession); 1172 1201 RTMemFree(pSession); 1202 1173 1203 /* Update the host flags (mouse status etc) not to reflect this session. */ 1174 1204 vboxGuestUpdateHostFlags(pDevExt, NULL, … … 1436 1466 int iEvent, const uint32_t fReqEvents) 1437 1467 { 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); 1439 1471 if (fMatches || pSession->fPendingCancelWaitEvents) 1440 1472 { 1473 ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches); 1441 1474 RTSpinlockRelease(pDevExt->EventSpinlock); 1442 1475 … … 1659 1692 case VMMDevReq_HGCMCancel2: 1660 1693 #endif /* VBOX_WITH_HGCM */ 1694 case VMMDevReq_SetGuestCapabilities: 1661 1695 default: 1662 1696 enmRequired = kLevel_NoOne; … … 1697 1731 break; 1698 1732 1699 /*1700 * Anyone. But not for CapsAcquire mode1701 */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 place1715 * 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 }1720 1733 /* 1721 1734 * Anyone. … … 2409 2422 */ 2410 2423 2411 static bool VBoxGuestCommonGuestCapsValidateValues(uint32_t fCaps)2412 {2413 if (fCaps & ~( VMMDEV_GUEST_SUPPORTS_SEAMLESS2414 | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING2415 | 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 of2422 * the currently listening sessions. In addition, report any events in2423 * @a fGenFakeEvents.2424 *2425 * @note This is called by GUEST_CAPS_ACQUIRE in case any pending events can now2426 * be dispatched to the session which acquired capabilities. The fake2427 * events are a hack to wake up threads in that session which would not2428 * otherwise be woken.2429 * @todo Why not just use CANCEL_ALL_WAITEVENTS to do the waking up rather than2430 * adding additional code to the driver?2431 * @todo Why does acquiring capabilities block and unblock events? Capabilities2432 * are supposed to control what is reported to the host, we already have2433 * 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_UP2453 RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);2454 #else2455 RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);2456 int rc = RTSemEventMultiSignal(pWait->Event);2457 AssertRC(rc);2458 #endif2459 if (!fEvents)2460 break;2461 }2462 }2463 ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents);2464 2465 RTSpinlockRelease(pDevExt->EventSpinlock);2466 2467 #ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP2468 VBoxGuestWaitDoWakeUps(pDevExt);2469 #endif2470 }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 acquired2475 * 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 valid2482 * 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 of2504 * capabilities currently in the other mode. Once a capability has been put in2505 * 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 else2516 {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 2529 2424 /** 2530 2425 * Sets the interrupt filter mask during initialization and termination. … … 2545 2440 if (RT_FAILURE(rc)) 2546 2441 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, so2555 * 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));2569 2442 return rc; 2570 2443 } … … 2595 2468 2596 2469 static int vboxGuestGetHostFlagsFromSessions(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, 2597 uint32_t *pfFilterMask, uint32_t *pf Capabilities, uint32_t *pfMouseStatus)2470 uint32_t *pfFilterMask, uint32_t *pfMouseStatus) 2598 2471 { 2599 2472 PVBOXGUESTSESSION pIterator; 2600 uint32_t fFilterMask = 0, fCapabilities = 0, fMouseStatus = 0; 2473 uint32_t fFilterMask = 0; 2474 uint32_t fMouseStatus = 0; 2601 2475 unsigned cSessions = 0; 2602 2476 int rc = VINF_SUCCESS; … … 2607 2481 { 2608 2482 fFilterMask |= pIterator->fFilterMask; 2609 fCapabilities |= pIterator->fCapabilities;2610 2483 fMouseStatus |= pIterator->fMouseStatus; 2611 2484 ++cSessions; 2612 2485 } 2613 2486 if (!cSessions) 2614 if (fFilterMask | f Capabilities | fMouseStatus)2487 if (fFilterMask | fMouseStatus) 2615 2488 rc = VERR_INTERNAL_ERROR; 2616 2489 if (cSessions == 1 && pSession) 2617 2490 if ( fFilterMask != pSession->fFilterMask 2618 || fCapabilities != pSession->fCapabilities2619 2491 || fMouseStatus != pSession->fMouseStatus) 2620 2492 rc = VERR_INTERNAL_ERROR; 2621 2493 if (cSessions > 1 && pSession) 2622 2494 if ( ~fFilterMask & pSession->fFilterMask 2623 || ~fCapabilities & pSession->fCapabilities2624 2495 || ~fMouseStatus & pSession->fMouseStatus) 2625 2496 rc = VERR_INTERNAL_ERROR; 2626 2497 *pfFilterMask = fFilterMask; 2627 *pfCapabilities = fCapabilities;2628 2498 *pfMouseStatus = fMouseStatus; 2629 2499 return rc; … … 2645 2515 int rc; 2646 2516 VMMDevCtlGuestFilterMask *pFilterReq = NULL; 2647 VMMDevReqGuestCapabilities2 *pCapabilitiesReq = NULL;2648 2517 VMMDevReqMouseStatus *pStatusReq = NULL; 2649 2518 uint32_t fFilterMask = 0; 2650 uint32_t fCapabilities = 0;2651 2519 uint32_t fMouseStatus = 0; 2652 2520 2653 2521 rc = VbglGRAlloc((VMMDevRequestHeader **)&pFilterReq, sizeof(*pFilterReq), 2654 2522 VMMDevReq_CtlGuestFilterMask); 2655 if (RT_SUCCESS(rc))2656 rc = VbglGRAlloc((VMMDevRequestHeader **)&pCapabilitiesReq,2657 sizeof(*pCapabilitiesReq),2658 VMMDevReq_SetGuestCapabilities);2659 2523 if (RT_SUCCESS(rc)) 2660 2524 rc = VbglGRAlloc((VMMDevRequestHeader **)&pStatusReq, … … 2663 2527 { 2664 2528 RTSpinlockAcquire(pDevExt->SessionSpinlock); 2665 rc = vboxGuestGetHostFlagsFromSessions(pDevExt, pSession, &fFilterMask, 2666 &fCapabilities, &fMouseStatus); 2529 rc = vboxGuestGetHostFlagsFromSessions(pDevExt, pSession, &fFilterMask, &fMouseStatus); 2667 2530 if (RT_SUCCESS(rc)) 2668 2531 { … … 2673 2536 if (fFlags & HostFlags_FilterMask) 2674 2537 vboxGuestSetFilterMask(pFilterReq, fFilterMask); 2675 fCapabilities |= pDevExt->u32GuestCaps;2676 if (fFlags & HostFlags_Capabilities)2677 vboxGuestSetCapabilities(pCapabilitiesReq, fCapabilities);2678 2538 if (fFlags & HostFlags_MouseStatus) 2679 2539 vboxGuestSetMouseStatus(pStatusReq, fMouseStatus); … … 2683 2543 if (pFilterReq) 2684 2544 VbglGRFree(&pFilterReq->header); 2685 if (pCapabilitiesReq)2686 VbglGRFree(&pCapabilitiesReq->header);2687 2545 if (pStatusReq) 2688 2546 VbglGRFree(&pStatusReq->header); 2547 2689 2548 return rc; 2690 2549 } 2691 2550 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 */ 2569 static 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 */ 2610 static 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 */ 2644 static 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 */ 2690 static 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", 2704 2710 pSession, fOrMask, fNotMask, enmFlags)); 2705 2711 return VERR_INVALID_PARAMETER; … … 2709 2715 && enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_NONE) 2710 2716 { 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", 2712 2718 pSession, fOrMask, fNotMask, enmFlags)); 2713 2719 return VERR_INVALID_PARAMETER; 2714 2720 } 2715 2721 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", 2719 2758 pSession, fOrMask, fNotMask, enmFlags)); 2720 2759 return VERR_INVALID_STATE; 2721 2760 } 2722 2761 2762 /* 2763 * If we only wanted to switch the capabilities into "acquire" mode, we're done now. 2764 */ 2723 2765 if (enmFlags & VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE) 2724 2766 { 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", 2726 2771 pSession, fOrMask, fNotMask, enmFlags)); 2727 2772 return VINF_SUCCESS; 2728 2773 } 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 */ 2741 2782 fCurrentOwnedCaps = pSession->u32AquiredGuestCaps; 2742 fSession NotCaps= fCurrentOwnedCaps & fNotMask;2743 fSession OrCaps= fOrMask & ~fCurrentOwnedCaps;2744 fOtherConflictingCaps = pDevExt->u32GuestCaps & ~fCurrentOwnedCaps;2745 fOtherConflictingCaps &= fSession OrCaps;2783 fSessionRemovedCaps = fCurrentOwnedCaps & fNotMask; 2784 fSessionAddedCaps = fOrMask & ~fCurrentOwnedCaps; 2785 fOtherConflictingCaps = pDevExt->u32GuestCapsAcquired & ~fCurrentOwnedCaps; 2786 fOtherConflictingCaps &= fSessionAddedCaps; 2746 2787 2747 2788 if (!fOtherConflictingCaps) 2748 2789 { 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; 2760 2839 } 2761 2840 2762 2841 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 } 2803 2869 2804 2870 return VINF_SUCCESS; … … 2806 2872 2807 2873 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 */ 2808 2883 static int VBoxGuestCommonIOCTL_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, 2809 2884 VBoxGuestCapsAquire *pAcquire) 2810 2885 { 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*/); 2812 2892 if (RT_FAILURE(rc)) 2813 2893 LogRel(("VBoxGuestCommonIOCtl: GUEST_CAPS_ACQUIRE failed rc=%Rrc\n", rc)); … … 2817 2897 2818 2898 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 */ 2910 static 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 */ 2819 2994 static int VBoxGuestCommonIOCtl_SetCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, 2820 2995 VBoxGuestSetCapabilitiesInfo *pInfo) 2821 2996 { 2822 2997 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 2831 3005 return rc; 2832 3006 } … … 3077 3251 3078 3252 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 */ 3261 static 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 3079 3300 3080 3301 /** … … 3163 3384 * Normal FIFO waiter evaluation. 3164 3385 */ 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); 3186 3387 } 3187 3388 else /* something is serious wrong... */ -
trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
r54296 r54601 163 163 * #SessionSpinlock lock. */ 164 164 RTLISTANCHOR SessionList; 165 /** Number of session. */ 166 uint32_t cSessions; 165 167 /** Flag indicating whether logging to the release log 166 168 * is enabled. */ … … 170 172 /** Callback and user data for a kernel mouse handler. */ 171 173 VBoxGuestMouseSetNotifyCallback MouseNotifyCallback; 174 175 /** @name Guest Capabilities. 176 * @{ */ 172 177 /** Guest capabilities which have been set to "acquire" mode. This means 173 178 * 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; 176 184 /** Guest capabilities which have been set to "set" mode. This just means 177 185 * that they have been blocked from ever being set to "acquire" mode. */ … … 179 187 /** Mask of all capabilities which are currently acquired by some session 180 188 * 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 182 197 /** Heartbeat timer which fires with interval 183 198 * cNsHearbeatInterval and its handler sends … … 230 245 * Use under the VBOXGUESTDEVEXT#SessionSpinlock lock. */ 231 246 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. */ 235 254 uint32_t fCapabilities; 236 255 /** Mouse features supported. A feature enabled in any guest session will … … 249 268 bool fOpened; 250 269 #endif 251 /** Mask of guest capabilities acquired by this session. These will all be252 * reported to the host. */253 uint32_t u32AquiredGuestCaps;254 270 /** Whether a CANCEL_ALL_WAITEVENTS is pending. This happens when 255 271 * CANCEL_ALL_WAITEVENTS is called, but no call to WAITEVENT is in process
Note:
See TracChangeset
for help on using the changeset viewer.