VBoxGuest.cpp revision 1ee3df76a5dc9c298a1c9b1a9d817c6db05bc43c
1124N/A * available from http://www.virtualbox.org. This file is free software;
#include "VBoxGuestInternal.h"
#include "VBoxGuest2.h"
#ifdef VBOX_WITH_HGCM
#include "version-generated.h"
# include "revision-generated.h"
#ifdef RT_OS_WINDOWS
# ifndef CTL_CODE
# include <Windows.h>
#ifdef VBOX_WITH_HGCM
static DECLCALLBACK(int) VBoxGuestHGCMAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdrNonVolatile, void *pvUser, uint32_t u32User);
static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags);
#define VBOXGUEST_ACQUIRE_STYLE_EVENTS (VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
DECLINLINE(uint32_t) VBoxGuestCommonGetHandledEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
return VMMDEV_EVENT_VALID_EVENT_MASK;
uint32_t u32AllowedGuestCaps = pSession->u32AquiredGuestCaps | (VMMDEV_EVENT_VALID_EVENT_MASK & ~pDevExt->u32AcquireModeGuestCaps);
DECLINLINE(uint32_t) VBoxGuestCommonGetAndCleanPendingEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fReqEvents)
uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents & VBoxGuestCommonGetHandledEventsLocked(pDevExt, pSession);
if (fMatches)
return fMatches;
DECLINLINE(bool) VBoxGuestCommonGuestCapsModeSet(PVBOXGUESTDEVEXT pDevExt, uint32_t fCaps, bool fAcquire, uint32_t *pu32OtherVal)
const uint32_t fNotVal = !fAcquire ? pDevExt->u32AcquireModeGuestCaps : pDevExt->u32SetModeGuestCaps;
bool fResult = true;
fResult = false;
if (pu32OtherVal)
return fResult;
return rc;
return rc;
return rc;
unsigned enmFlags)
unsigned cSessions = 0;
++cSessions;
if (!cSessions)
return rc;
static const size_t cbChangeMemBalloonReq = RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]);
int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevReqHypervisorInfo), VMMDevReq_GetHypervisorInfo);
return rc;
return rc;
bool fBitched = false;
rc = RTR0MemObjEnterPhys(&hObj, VBOXGUEST_HYPERVISOR_PHYSICAL_START, cbHypervisor + _4M, RTMEM_CACHE_POLICY_DONT_CARE);
rc = RTR0MemObjMapKernel(&hObj, hFictive, (void *)-1, uAlignment, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
rc = RTR0MemObjMapKernel(&hObj, hFictive, (void *)-1, uAlignment, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
LogRel(("VBoxGuest: Failed to reserve memory for the hypervisor: rc=%Rrc (cbHypervisor=%#x uAlignment=%#x iTry=%u)\n",
fBitched = true;
AssertMsg(RT_ALIGN_32(pReq->hypervisorStart, _4M) == pReq->hypervisorStart, ("%#x\n", pReq->hypervisorStart));
while (iTry-- > 0)
LogRel(("VBoxGuest: Warning: failed to reserve %#d of memory for guest mappings.\n", cbHypervisor));
return VINF_SUCCESS;
int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevReqHypervisorInfo), VMMDevReq_SetHypervisorInfo);
int rc;
return rc;
int rc;
return rc;
LogRel(("vboxGuestBalloonDeflate: RTR0MemObjFree(%p,true) -> %Rrc; this is *BAD*!\n", *pMemObj, rc));
return rc;
return VINF_SUCCESS;
static int vboxGuestSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt, uint32_t cBalloonChunks, uint32_t *pfHandleInR3)
uint32_t i;
return VERR_INVALID_PARAMETER;
pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAllocZ(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
return VERR_NO_MEMORY;
return rc;
return rc;
Log(("VBoxGuest::VBoxGuestReinitDevExtAfterHibernation: could not report guest driver status, rc=%Rrc\n", rc));
Log(("VBoxGuest::VBoxGuestReinitDevExtAfterHibernation: could not report guest information to host, rc=%Rrc\n", rc));
return rc;
uint32_t i;
if (fInflate)
return VERR_INVALID_PARAMETER;
pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAlloc(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
return VERR_NO_MEMORY;
return VERR_INVALID_PARAMETER;
if ( fInflate
&& !pMemObj
if (fInflate)
if (!pMemObj)
if (fInflate)
return VERR_NO_MEMORY;
return VERR_NOT_FOUND;
return rc;
if (fInflate)
return rc;
int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, cbChangeMemBalloonReq, VMMDevReq_ChangeMemBalloon);
uint32_t i;
LogRel(("vboxGuestCloseMemBalloon: Failed to allocate VMMDev request buffer (rc=%Rrc). Will leak %u chunks.\n",
"VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
#ifdef VBOX_WITH_HGCM
#ifdef VBOX_WITH_HGCM
if (pvMMIOBase)
LogRel(("VBoxGuestInitDevExt: Bogus VMMDev memory; u32Version=%RX32 (expected %RX32) u32Size=%RX32 (expected <= %RX32)\n",
rc = RTSpinlockCreate(&pDevExt->SessionSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestSession");
return rc;
return rc;
rc = VbglGRAlloc((VMMDevRequestHeader **)&pDevExt->pIrqAckEvents, sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
return VINF_SUCCESS;
int rc2;
int rc2;
#ifdef VBOX_WITH_HGCM
return VERR_NO_MEMORY;
pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
return VINF_SUCCESS;
return VERR_NO_MEMORY;
pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
return VINF_SUCCESS;
static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
unsigned i; NOREF(i);
pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
#ifdef VBOX_WITH_HGCM
if (pWait)
if (pWait)
if (!pWait)
static unsigned s_cErrors = 0;
int rc;
if (!pWait)
return NULL;
return NULL;
#ifdef VBOX_WITH_HGCM
return pWait;
#ifdef VBOX_WITH_HGCM
int rc;
if (!pWait)
Log(("VBoxGuestSetGuestCapabilities: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
return rc;
return rc;
int VBoxGuestCommonIOCtlFast(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
Log(("VBoxGuestCommonIOCtlFast: iFunction=%#x pDevExt=%p pSession=%p\n", iFunction, pDevExt, pSession));
return VERR_NOT_SUPPORTED;
static int VBoxGuestCommonIOCtl_GetVMMDevPort(PVBOXGUESTDEVEXT pDevExt, VBoxGuestPortInfo *pInfo, size_t *pcbDataReturned)
if (pcbDataReturned)
return VINF_SUCCESS;
#ifndef RT_OS_WINDOWS
int VBoxGuestCommonIOCtl_SetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGuestMouseSetNotifyCallback *pNotify)
return VINF_SUCCESS;
DECLINLINE(int) WaitEventCheckCondition(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestWaitEventInfo *pInfo,
return VINF_SUCCESS;
return VERR_TIMEOUT;
int iEvent;
int rc;
if (pcbDataReturned)
return VERR_INVALID_PARAMETER;
return rc;
return VERR_TIMEOUT;
if (!pWait)
return VERR_NO_MEMORY;
return rc;
if (fInterruptible)
return rc;
if ( fResEvents
static unsigned s_cErrors = 0;
return rc;
static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
int rc = 0;
bool fCancelledOne = false;
fCancelledOne = true;
if (!fCancelledOne)
return VINF_SUCCESS;
static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VMMDevRequestType enmType,
kLevel_Invalid, kLevel_NoOne, kLevel_OnlyVBoxGuest, kLevel_OnlyKernel, kLevel_TrustedUsers, kLevel_AllUsers
} enmRequired;
switch (enmType)
#ifdef VBOX_WITH_HGCM
case VMMDevReq_HGCMConnect:
case VMMDevReq_HGCMDisconnect:
# ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevReq_HGCMCall32:
case VMMDevReq_HGCMCall64:
case VMMDevReq_HGCMCall:
case VMMDevReq_HGCMCancel:
case VMMDevReq_HGCMCancel2:
case VMMDevReq_WriteCoreDump:
AssertFailed();
case VMMDevReq_GetMouseStatus:
case VMMDevReq_SetMouseStatus:
case VMMDevReq_GetHostVersion:
case VMMDevReq_Idle:
case VMMDevReq_GetHostTime:
case VMMDevReq_SetPowerStatus:
case VMMDevReq_LogString:
case VMMDevReq_GetSessionId:
switch (enmRequired)
case kLevel_NoOne:
case kLevel_OnlyVBoxGuest:
case kLevel_OnlyKernel:
return VINF_SUCCESS;
case kLevel_TrustedUsers:
case kLevel_AllUsers:
return VINF_SUCCESS;
return VERR_PERMISSION_DENIED;
int rc;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
Log(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid header: size %#x, expected >= %#x (hdr); type=%#x; rc=%Rrc!!\n",
return rc;
return rc;
Log(("VBoxGuestCommonIOCtl: VMMREQUEST: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
return rc;
if (pcbDataReturned)
Log(("VBoxGuestCommonIOCtl: VMMREQUEST: request execution failed; VMMDev rc=%Rrc!\n", pReqCopy->rc));
return rc;
int rc;
return VERR_INVALID_PARAMETER;
return rc;
int rc;
return VERR_INVALID_PARAMETER;
return rc;
int rc;
return VERR_INVALID_PARAMETER;
return rc;
#ifdef VBOX_WITH_HGCM
static int VBoxGuestHGCMAsyncWaitCallbackWorker(VMMDevHGCMRequestHeader volatile *pHdr, PVBOXGUESTDEVEXT pDevExt,
int rc;
return VINF_SUCCESS;
if (pWait)
if (fInterruptible)
return VERR_INTERRUPTED;
return VINF_SUCCESS;
if (fInterruptible)
return rc;
&& ( !fInterruptible
return rc;
static DECLCALLBACK(int) VBoxGuestHGCMAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdr, void *pvUser, uint32_t u32User)
int rc;
static unsigned s_cErrors = 0;
return VERR_TOO_MANY_OPEN_FILES;
if (pcbDataReturned)
return rc;
static int VBoxGuestCommonIOCtl_HGCMDisconnect(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestHGCMDisconnectInfo *pInfo,
int rc;
static unsigned s_cErrors = 0;
return VERR_INVALID_HANDLE;
rc = VbglR0HGCMInternalDisconnect(pInfo, VBoxGuestHGCMAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
if (pcbDataReturned)
return rc;
int rc;
return VERR_INVALID_PARAMETER;
#ifdef RT_ARCH_AMD64
if (f32bit)
return VERR_INVALID_PARAMETER;
static unsigned s_cErrors = 0;
return VERR_INVALID_HANDLE;
fFlags = !fUserData && pSession->R0Process == NIL_RTR0PROCESS ? VBGLR0_HGCMCALL_F_KERNEL : VBGLR0_HGCMCALL_F_USER;
#ifdef RT_ARCH_AMD64
if (f32bit)
if (fInterruptible)
rc = VbglR0HGCMInternalCall32(pInfo, cbData - cbExtra, fFlags, VBoxGuestHGCMAsyncWaitCallbackInterruptible, pDevExt, cMillies);
rc = VbglR0HGCMInternalCall32(pInfo, cbData - cbExtra, fFlags, VBoxGuestHGCMAsyncWaitCallback, pDevExt, cMillies);
if (fInterruptible)
rc = VbglR0HGCMInternalCall(pInfo, cbData - cbExtra, fFlags, VBoxGuestHGCMAsyncWaitCallbackInterruptible, pDevExt, cMillies);
rc = VbglR0HGCMInternalCall(pInfo, cbData - cbExtra, fFlags, VBoxGuestHGCMAsyncWaitCallback, pDevExt, cMillies);
if (pcbDataReturned)
static unsigned s_cErrors = 0;
return rc;
static int VBoxGuestCommonIOCtl_CheckMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
int rc;
rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevGetMemBalloonChangeRequest), VMMDevReq_GetMemBalloonChangeRequest);
Assert(pDevExt->MemBalloon.cMaxChunks == pReq->cPhysMemChunks || pDevExt->MemBalloon.cMaxChunks == 0);
if (pcbDataReturned)
return rc;
static int VBoxGuestCommonIOCtl_ChangeMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
if (pcbDataReturned)
*pcbDataReturned = 0;
return rc;
static int VBoxGuestCommonIOCtl_WriteCoreDump(PVBOXGUESTDEVEXT pDevExt, VBoxGuestWriteCoreDump *pInfo)
Log(("VBoxGuestCommonIOCtl: WRITE_CORE_DUMP: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
return rc;
return rc;
static int VBoxGuestCommonIOCtl_EnableVRDPSession(VBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
return VERR_NOT_IMPLEMENTED;
static int VBoxGuestCommonIOCtl_DisableVRDPSession(VBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
return VERR_NOT_IMPLEMENTED;
static int VBoxGuestCommonIOCtl_Log(PVBOXGUESTDEVEXT pDevExt, const char *pch, size_t cbData, size_t *pcbDataReturned)
if (pcbDataReturned)
*pcbDataReturned = 0;
return VINF_SUCCESS;
if (fCaps & (~(VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING | VMMDEV_GUEST_SUPPORTS_GRAPHICS)))
static void VBoxGuestCommonCheckEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fGenFakeEvents)
if (!fEvents)
static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags)
LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid fOrMask\n",
return VERR_INVALID_PARAMETER;
LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid enmFlags %d\n",
return VERR_INVALID_PARAMETER;
LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- calling caps acquire for set caps\n",
return VERR_INVALID_STATE;
Log(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- configured acquire caps: 0x%x\n",
return VINF_SUCCESS;
if (!fOtherConflictingCaps)
if (fSessionOrCaps)
if (fSessionNotCaps)
return VERR_RESOURCE_BUSY;
return VINF_SUCCESS;
* this is generally bad since e.g. failure to release the caps may result in other sessions not being able to use it
* so we are not trying to restore the caps back to their values before the VBoxGuestCommonGuestCapsAcquire call,
/* since the acquire filter mask has changed, we need to process events in any way to ensure they go from pending events field
return VINF_SUCCESS;
static int VBoxGuestCommonIOCTL_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestCapsAquire *pAcquire)
int rc = VBoxGuestCommonGuestCapsAcquire(pDevExt, pSession, pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags);
return VINF_SUCCESS;
int rc;
if (pcbDataReturned)
*pcbDataReturned = 0;
return VERR_PERMISSION_DENIED; \
return VERR_BUFFER_OVERFLOW; \
return VERR_INVALID_POINTER; \
return VERR_BUFFER_OVERFLOW; \
return VERR_INVALID_POINTER; \
if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0)))
rc = VBoxGuestCommonIOCtl_VMMRequest(pDevExt, pSession, (VMMDevRequestHeader *)pvData, cbData, pcbDataReturned);
#ifdef VBOX_WITH_HGCM
else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0)))
rc = VBoxGuestCommonIOCtl_HGCMCall(pDevExt, pSession, (VBoxGuestHGCMCallInfo *)pvData, RT_INDEFINITE_WAIT,
else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0)))
else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_USERDATA(0)))
bool fInterruptible = true;
rc = VBoxGuestCommonIOCtl_HGCMCall(pDevExt, pSession, (VBoxGuestHGCMCallInfo *)pvData, RT_INDEFINITE_WAIT,
# ifdef RT_ARCH_AMD64
else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_32(0)))
rc = VBoxGuestCommonIOCtl_HGCMCall(pDevExt, pSession, (VBoxGuestHGCMCallInfo *)pvData, RT_INDEFINITE_WAIT,
else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED_32(0)))
else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0)))
switch (iFunction)
rc = VBoxGuestCommonIOCtl_SetMouseNotifyCallback(pDevExt, (VBoxGuestMouseSetNotifyCallback *)pvData);
if (cbData != 0)
sizeof(VBoxGuestFilterMaskInfo));
#ifdef VBOX_WITH_HGCM
# ifdef RT_ARCH_AMD64
rc = VBoxGuestCommonIOCtl_HGCMConnect(pDevExt, pSession, (VBoxGuestHGCMConnectInfo *)pvData, pcbDataReturned);
# ifdef RT_ARCH_AMD64
rc = VBoxGuestCommonIOCtl_HGCMDisconnect(pDevExt, pSession, (VBoxGuestHGCMDisconnectInfo *)pvData, pcbDataReturned);
rc = VBoxGuestCommonIOCtl_CheckMemoryBalloon(pDevExt, pSession, (VBoxGuestCheckBalloonInfo *)pvData, pcbDataReturned);
rc = VBoxGuestCommonIOCtl_ChangeMemoryBalloon(pDevExt, pSession, (VBoxGuestChangeBalloonInfo *)pvData, pcbDataReturned);
sizeof(VBoxGuestSetCapabilitiesInfo));
Log(("VBoxGuestCommonIOCtl: returns %Rrc *pcbDataReturned=%zu\n", rc, pcbDataReturned ? *pcbDataReturned : 0));
return rc;
bool fMousePositionChanged = false;
int rc = 0;
bool fOurIrq;
if (fOurIrq)
fMousePositionChanged = true;
#ifndef RT_OS_WINDOWS
#ifdef VBOX_WITH_HGCM
# ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
if (!fEvents)
return fOurIrq;