diff options
Diffstat (limited to 'src/VBox/Main/src-client/VMMDevInterface.cpp')
-rw-r--r-- | src/VBox/Main/src-client/VMMDevInterface.cpp | 1265 |
1 files changed, 1265 insertions, 0 deletions
diff --git a/src/VBox/Main/src-client/VMMDevInterface.cpp b/src/VBox/Main/src-client/VMMDevInterface.cpp new file mode 100644 index 00000000..e8c0011d --- /dev/null +++ b/src/VBox/Main/src-client/VMMDevInterface.cpp @@ -0,0 +1,1265 @@ +/* $Id: VMMDevInterface.cpp $ */ +/** @file + * VirtualBox Driver Interface to VMM device. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_GROUP LOG_GROUP_MAIN_VMMDEVINTERFACES +#include "LoggingNew.h" + +#include "VMMDev.h" +#include "ConsoleImpl.h" +#include "DisplayImpl.h" +#include "GuestImpl.h" +#include "MouseImpl.h" + +#include <VBox/vmm/pdmdrv.h> +#include <VBox/VMMDev.h> +#include <VBox/shflsvc.h> +#include <iprt/asm.h> + +#ifdef VBOX_WITH_HGCM +# include "HGCM.h" +# include "HGCMObjects.h" +#endif + +// +// defines +// + +#ifdef RT_OS_OS2 +# define VBOXSHAREDFOLDERS_DLL "VBoxSFld" +#else +# define VBOXSHAREDFOLDERS_DLL "VBoxSharedFolders" +#endif + +// +// globals +// + + +/** + * VMMDev driver instance data. + */ +typedef struct DRVMAINVMMDEV +{ + /** Pointer to the VMMDev object. */ + VMMDev *pVMMDev; + /** Pointer to the driver instance structure. */ + PPDMDRVINS pDrvIns; + /** Pointer to the VMMDev port interface of the driver/device above us. */ + PPDMIVMMDEVPORT pUpPort; + /** Our VMM device connector interface. */ + PDMIVMMDEVCONNECTOR Connector; + +#ifdef VBOX_WITH_HGCM + /** Pointer to the HGCM port interface of the driver/device above us. */ + PPDMIHGCMPORT pHGCMPort; + /** Our HGCM connector interface. */ + PDMIHGCMCONNECTOR HGCMConnector; +#endif + +#ifdef VBOX_WITH_GUEST_PROPS + HGCMSVCEXTHANDLE hHgcmSvcExtGstProps; +#endif +#ifdef VBOX_WITH_GUEST_CONTROL + HGCMSVCEXTHANDLE hHgcmSvcExtGstCtrl; +#endif +} DRVMAINVMMDEV, *PDRVMAINVMMDEV; + +// +// constructor / destructor +// +VMMDev::VMMDev(Console *console) + : mpDrv(NULL) + , mParent(console) +{ + int vrc = RTSemEventCreate(&mCredentialsEvent); + AssertRC(vrc); +#ifdef VBOX_WITH_HGCM + vrc = HGCMHostInit(); + AssertRC(vrc); + m_fHGCMActive = true; +#endif /* VBOX_WITH_HGCM */ + mu32CredentialsFlags = 0; +} + +VMMDev::~VMMDev() +{ +#ifdef VBOX_WITH_HGCM + if (ASMAtomicCmpXchgBool(&m_fHGCMActive, false, true)) + HGCMHostShutdown(true /*fUvmIsInvalid*/); +#endif + RTSemEventDestroy(mCredentialsEvent); + if (mpDrv) + mpDrv->pVMMDev = NULL; + mpDrv = NULL; +} + +PPDMIVMMDEVPORT VMMDev::getVMMDevPort() +{ + if (!mpDrv) + return NULL; + return mpDrv->pUpPort; +} + + + +// +// public methods +// + +/** + * Wait on event semaphore for guest credential judgement result. + */ +int VMMDev::WaitCredentialsJudgement(uint32_t u32Timeout, uint32_t *pu32CredentialsFlags) +{ + if (u32Timeout == 0) + { + u32Timeout = 5000; + } + + int vrc = RTSemEventWait(mCredentialsEvent, u32Timeout); + + if (RT_SUCCESS(vrc)) + { + *pu32CredentialsFlags = mu32CredentialsFlags; + } + + return vrc; +} + +int VMMDev::SetCredentialsJudgementResult(uint32_t u32Flags) +{ + mu32CredentialsFlags = u32Flags; + + int vrc = RTSemEventSignal(mCredentialsEvent); + AssertRC(vrc); + + return vrc; +} + + +/** + * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateGuestStatus} + */ +DECLCALLBACK(void) vmmdevUpdateGuestStatus(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFacility, uint16_t uStatus, + uint32_t fFlags, PCRTTIMESPEC pTimeSpecTS) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + /* Store that information in IGuest */ + Guest* guest = pConsole->i_getGuest(); + AssertPtrReturnVoid(guest); + + guest->i_setAdditionsStatus((VBoxGuestFacilityType)uFacility, (VBoxGuestFacilityStatus)uStatus, fFlags, pTimeSpecTS); + pConsole->i_onAdditionsStateChange(); +} + + +/** + * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateGuestUserState} + */ +DECLCALLBACK(void) vmmdevUpdateGuestUserState(PPDMIVMMDEVCONNECTOR pInterface, + const char *pszUser, const char *pszDomain, + uint32_t uState, + const uint8_t *pabDetails, uint32_t cbDetails) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + AssertPtr(pDrv); + Console *pConsole = pDrv->pVMMDev->getParent(); + AssertPtr(pConsole); + + /* Store that information in IGuest. */ + Guest* pGuest = pConsole->i_getGuest(); + AssertPtrReturnVoid(pGuest); + + pGuest->i_onUserStateChanged(Utf8Str(pszUser), Utf8Str(pszDomain), (VBoxGuestUserState)uState, pabDetails, cbDetails); +} + + +/** + * Reports Guest Additions API and OS version. + * + * Called whenever the Additions issue a guest version report request or the VM + * is reset. + * + * @param pInterface Pointer to this interface. + * @param guestInfo Pointer to guest information structure. + * @thread The emulation thread. + */ +DECLCALLBACK(void) vmmdevUpdateGuestInfo(PPDMIVMMDEVCONNECTOR pInterface, const VBoxGuestInfo *guestInfo) +{ + AssertPtrReturnVoid(guestInfo); + + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + /* Store that information in IGuest */ + Guest* guest = pConsole->i_getGuest(); + AssertPtrReturnVoid(guest); + + if (guestInfo->interfaceVersion != 0) + { + char version[16]; + RTStrPrintf(version, sizeof(version), "%d", guestInfo->interfaceVersion); + guest->i_setAdditionsInfo(Bstr(version), guestInfo->osType); + + /* + * Tell the console interface about the event + * so that it can notify its consumers. + */ + pConsole->i_onAdditionsStateChange(); + + if (guestInfo->interfaceVersion < VMMDEV_VERSION) + pConsole->i_onAdditionsOutdated(); + } + else + { + /* + * The Guest Additions was disabled because of a reset + * or driver unload. + */ + guest->i_setAdditionsInfo(Bstr(), guestInfo->osType); /* Clear interface version + OS type. */ + /** @todo Would be better if GuestImpl.cpp did all this in the above method call + * while holding down the. */ + guest->i_setAdditionsInfo2(0, "", 0, 0); /* Clear Guest Additions version. */ + RTTIMESPEC TimeSpecTS; + RTTimeNow(&TimeSpecTS); + guest->i_setAdditionsStatus(VBoxGuestFacilityType_All, VBoxGuestFacilityStatus_Inactive, 0 /*fFlags*/, &TimeSpecTS); + pConsole->i_onAdditionsStateChange(); + } +} + +/** + * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateGuestInfo2} + */ +DECLCALLBACK(void) vmmdevUpdateGuestInfo2(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFullVersion, + const char *pszName, uint32_t uRevision, uint32_t fFeatures) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + AssertPtr(pszName); + Assert(uFullVersion); + + /* Store that information in IGuest. */ + Guest *pGuest = pDrv->pVMMDev->getParent()->i_getGuest(); + AssertPtrReturnVoid(pGuest); + + /* Just pass it on... */ + pGuest->i_setAdditionsInfo2(uFullVersion, pszName, uRevision, fFeatures); + + /* + * No need to tell the console interface about the update; + * vmmdevUpdateGuestInfo takes care of that when called as the + * last event in the chain. + */ +} + +/** + * Update the Guest Additions capabilities. + * This is called when the Guest Additions capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param newCapabilities New capabilities. + * @thread The emulation thread. + */ +DECLCALLBACK(void) vmmdevUpdateGuestCapabilities(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + AssertPtr(pDrv); + Console *pConsole = pDrv->pVMMDev->getParent(); + + /* store that information in IGuest */ + Guest* pGuest = pConsole->i_getGuest(); + AssertPtrReturnVoid(pGuest); + + /* + * Report our current capabilities (and assume none is active yet). + */ + pGuest->i_setSupportedFeatures(newCapabilities); + + /* + * Tell the Display, so that it can update the "supports graphics" + * capability if the graphics card has not asserted it. + */ + Display* pDisplay = pConsole->i_getDisplay(); + AssertPtrReturnVoid(pDisplay); + pDisplay->i_handleUpdateVMMDevSupportsGraphics(RT_BOOL(newCapabilities & VMMDEV_GUEST_SUPPORTS_GRAPHICS)); + + /* + * Tell the console interface about the event + * so that it can notify its consumers. + */ + pConsole->i_onAdditionsStateChange(); +} + +/** + * Update the mouse capabilities. + * This is called when the mouse capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param fNewCaps New capabilities. + * @thread The emulation thread. + */ +DECLCALLBACK(void) vmmdevUpdateMouseCapabilities(PPDMIVMMDEVCONNECTOR pInterface, uint32_t fNewCaps) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + /* + * Tell the console interface about the event + * so that it can notify its consumers. + */ + Mouse *pMouse = pConsole->i_getMouse(); + if (pMouse) /** @todo and if not? Can that actually happen? */ + pMouse->i_onVMMDevGuestCapsChange(fNewCaps & VMMDEV_MOUSE_GUEST_MASK); +} + +/** + * Update the pointer shape or visibility. + * + * This is called when the mouse pointer shape changes or pointer is hidden/displaying. + * The new shape is passed as a caller allocated buffer that will be freed after returning. + * + * @param pInterface Pointer to this interface. + * @param fVisible Whether the pointer is visible or not. + * @param fAlpha Alpha channel information is present. + * @param xHot Horizontal coordinate of the pointer hot spot. + * @param yHot Vertical coordinate of the pointer hot spot. + * @param width Pointer width in pixels. + * @param height Pointer height in pixels. + * @param pShape The shape buffer. If NULL, then only pointer visibility is being changed. + * @thread The emulation thread. + */ +DECLCALLBACK(void) vmmdevUpdatePointerShape(PPDMIVMMDEVCONNECTOR pInterface, bool fVisible, bool fAlpha, + uint32_t xHot, uint32_t yHot, + uint32_t width, uint32_t height, + void *pShape) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + /* tell the console about it */ + uint32_t cbShape = 0; + if (pShape) + { + cbShape = (width + 7) / 8 * height; /* size of the AND mask */ + cbShape = ((cbShape + 3) & ~3) + width * 4 * height; /* + gap + size of the XOR mask */ + } + pConsole->i_onMousePointerShapeChange(fVisible, fAlpha, xHot, yHot, width, height, (uint8_t *)pShape, cbShape); +} + +DECLCALLBACK(int) iface_VideoAccelEnable(PPDMIVMMDEVCONNECTOR pInterface, bool fEnable, VBVAMEMORY *pVbvaMemory) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + Display *display = pConsole->i_getDisplay(); + + if (display) + { + Log9(("MAIN::VMMDevInterface::iface_VideoAccelEnable: %d, %p\n", fEnable, pVbvaMemory)); + return display->VideoAccelEnableVMMDev(fEnable, pVbvaMemory); + } + + return VERR_NOT_SUPPORTED; +} +DECLCALLBACK(void) iface_VideoAccelFlush(PPDMIVMMDEVCONNECTOR pInterface) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + Display *display = pConsole->i_getDisplay(); + + if (display) + { + Log9(("MAIN::VMMDevInterface::iface_VideoAccelFlush\n")); + display->VideoAccelFlushVMMDev(); + } +} + +DECLCALLBACK(int) vmmdevVideoModeSupported(PPDMIVMMDEVCONNECTOR pInterface, uint32_t display, uint32_t width, uint32_t height, + uint32_t bpp, bool *fSupported) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + if (!fSupported) + return VERR_INVALID_PARAMETER; +#ifdef DEBUG_sunlover + Log(("vmmdevVideoModeSupported: [%d]: %dx%dx%d\n", display, width, height, bpp)); +#endif + IFramebuffer *framebuffer = NULL; + HRESULT hrc = pConsole->i_getDisplay()->QueryFramebuffer(display, &framebuffer); + if (SUCCEEDED(hrc) && framebuffer) + { + framebuffer->VideoModeSupported(width, height, bpp, (BOOL*)fSupported); + framebuffer->Release(); + } + else + { +#ifdef DEBUG_sunlover + Log(("vmmdevVideoModeSupported: hrc %x, framebuffer %p!!!\n", hrc, framebuffer)); +#endif + *fSupported = true; + } + return VINF_SUCCESS; +} + +DECLCALLBACK(int) vmmdevGetHeightReduction(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *heightReduction) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + if (!heightReduction) + return VERR_INVALID_PARAMETER; + IFramebuffer *framebuffer = NULL; + HRESULT hrc = pConsole->i_getDisplay()->QueryFramebuffer(0, &framebuffer); + if (SUCCEEDED(hrc) && framebuffer) + { + framebuffer->COMGETTER(HeightReduction)((ULONG*)heightReduction); + framebuffer->Release(); + } + else + *heightReduction = 0; + return VINF_SUCCESS; +} + +DECLCALLBACK(int) vmmdevSetCredentialsJudgementResult(PPDMIVMMDEVCONNECTOR pInterface, uint32_t u32Flags) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + + if (pDrv->pVMMDev) + return pDrv->pVMMDev->SetCredentialsJudgementResult(u32Flags); + + return VERR_GENERAL_FAILURE; +} + +DECLCALLBACK(int) vmmdevSetVisibleRegion(PPDMIVMMDEVCONNECTOR pInterface, uint32_t cRect, PRTRECT pRect) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + /* Forward to Display, which calls corresponding framebuffers. */ + pConsole->i_getDisplay()->i_handleSetVisibleRegion(cRect, pRect); + + return VINF_SUCCESS; +} + +/** + * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateMonitorPositions} + */ +static DECLCALLBACK(int) vmmdevUpdateMonitorPositions(PPDMIVMMDEVCONNECTOR pInterface, uint32_t cPositions, PCRTPOINT paPositions) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + pConsole->i_getDisplay()->i_handleUpdateMonitorPositions(cPositions, paPositions); + + return VINF_SUCCESS; +} + +DECLCALLBACK(int) vmmdevQueryVisibleRegion(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcRects, PRTRECT paRects) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + /* Forward to Display, which calls corresponding framebuffers. */ + pConsole->i_getDisplay()->i_handleQueryVisibleRegion(pcRects, paRects); + + return VINF_SUCCESS; +} + +/** + * Request the statistics interval + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pulInterval Pointer to interval in seconds + * @thread The emulation thread. + */ +DECLCALLBACK(int) vmmdevQueryStatisticsInterval(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pulInterval) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + ULONG val = 0; + + if (!pulInterval) + return VERR_INVALID_POINTER; + + /* store that information in IGuest */ + Guest* guest = pConsole->i_getGuest(); + AssertPtrReturn(guest, VERR_GENERAL_FAILURE); + + guest->COMGETTER(StatisticsUpdateInterval)(&val); + *pulInterval = val; + return VINF_SUCCESS; +} + +/** + * Query the current balloon size + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcbBalloon Balloon size + * @thread The emulation thread. + */ +DECLCALLBACK(int) vmmdevQueryBalloonSize(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcbBalloon) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + ULONG val = 0; + + if (!pcbBalloon) + return VERR_INVALID_POINTER; + + /* store that information in IGuest */ + Guest* guest = pConsole->i_getGuest(); + AssertPtrReturn(guest, VERR_GENERAL_FAILURE); + + guest->COMGETTER(MemoryBalloonSize)(&val); + *pcbBalloon = val; + return VINF_SUCCESS; +} + +/** + * Query the current page fusion setting + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pfPageFusionEnabled Pointer to boolean + * @thread The emulation thread. + */ +DECLCALLBACK(int) vmmdevIsPageFusionEnabled(PPDMIVMMDEVCONNECTOR pInterface, bool *pfPageFusionEnabled) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + if (!pfPageFusionEnabled) + return VERR_INVALID_POINTER; + + /* store that information in IGuest */ + Guest* guest = pConsole->i_getGuest(); + AssertPtrReturn(guest, VERR_GENERAL_FAILURE); + + *pfPageFusionEnabled = !!guest->i_isPageFusionEnabled(); + return VINF_SUCCESS; +} + +/** + * Report new guest statistics + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pGuestStats Guest statistics + * @thread The emulation thread. + */ +DECLCALLBACK(int) vmmdevReportStatistics(PPDMIVMMDEVCONNECTOR pInterface, VBoxGuestStatistics *pGuestStats) +{ + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector); + Console *pConsole = pDrv->pVMMDev->getParent(); + + AssertPtrReturn(pGuestStats, VERR_INVALID_POINTER); + + /* store that information in IGuest */ + Guest* guest = pConsole->i_getGuest(); + AssertPtrReturn(guest, VERR_GENERAL_FAILURE); + + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_CPUIDLE, pGuestStats->u32CpuLoad_Idle); + + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_CPUKERNEL, pGuestStats->u32CpuLoad_Kernel); + + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_CPUUSER, pGuestStats->u32CpuLoad_User); + + + /** @todo r=bird: Convert from 4KB to 1KB units? + * CollectorGuestHAL::i_getGuestMemLoad says it returns KB units to + * preCollect(). I might be wrong ofc, this is convoluted code... */ + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMTOTAL, pGuestStats->u32PhysMemTotal); + + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMFREE, pGuestStats->u32PhysMemAvail); + + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMBALLOON, pGuestStats->u32PhysMemBalloon); + + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMCACHE, pGuestStats->u32MemSystemCache); + + if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE) + guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_PAGETOTAL, pGuestStats->u32PageFileSize); + + return VINF_SUCCESS; +} + +#ifdef VBOX_WITH_HGCM + +/* HGCM connector interface */ + +static DECLCALLBACK(int) iface_hgcmConnect(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, + PHGCMSERVICELOCATION pServiceLocation, + uint32_t *pu32ClientID) +{ + Log9(("Enter\n")); + + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector); + + if ( !pServiceLocation + || ( pServiceLocation->type != VMMDevHGCMLoc_LocalHost + && pServiceLocation->type != VMMDevHGCMLoc_LocalHost_Existing)) + { + return VERR_INVALID_PARAMETER; + } + + /* Check if service name is a string terminated by zero*/ + size_t cchInfo = 0; + if (RTStrNLenEx(pServiceLocation->u.host.achName, sizeof(pServiceLocation->u.host.achName), &cchInfo) != VINF_SUCCESS) + { + return VERR_INVALID_PARAMETER; + } + + if (!pDrv->pVMMDev || !pDrv->pVMMDev->hgcmIsActive()) + return VERR_INVALID_STATE; + return HGCMGuestConnect(pDrv->pHGCMPort, pCmd, pServiceLocation->u.host.achName, pu32ClientID); +} + +static DECLCALLBACK(int) iface_hgcmDisconnect(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID) +{ + Log9(("Enter\n")); + + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector); + + if (!pDrv->pVMMDev || !pDrv->pVMMDev->hgcmIsActive()) + return VERR_INVALID_STATE; + + return HGCMGuestDisconnect(pDrv->pHGCMPort, pCmd, u32ClientID); +} + +static DECLCALLBACK(int) iface_hgcmCall(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, + uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms, uint64_t tsArrival) +{ + Log9(("Enter\n")); + + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector); + + if (!pDrv->pVMMDev || !pDrv->pVMMDev->hgcmIsActive()) + return VERR_INVALID_STATE; + + return HGCMGuestCall(pDrv->pHGCMPort, pCmd, u32ClientID, u32Function, cParms, paParms, tsArrival); +} + +static DECLCALLBACK(void) iface_hgcmCancelled(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t idClient) +{ + Log9(("Enter\n")); + + PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector); + if ( pDrv->pVMMDev + && pDrv->pVMMDev->hgcmIsActive()) + return HGCMGuestCancelled(pDrv->pHGCMPort, pCmd, idClient); +} + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +/*static*/ DECLCALLBACK(int) VMMDev::hgcmSave(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM) +{ + PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); + Log9(("Enter\n")); + + AssertReturn(pThis->pVMMDev, VERR_INTERNAL_ERROR_2); + Console::SafeVMPtrQuiet ptrVM(pThis->pVMMDev->mParent); + AssertReturn(ptrVM.isOk(), VERR_INTERNAL_ERROR_3); + return HGCMHostSaveState(pSSM, ptrVM.vtable()); +} + + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The data pass. + */ +/*static*/ DECLCALLBACK(int) VMMDev::hgcmLoad(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) +{ + PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); + LogFlowFunc(("Enter\n")); + + if ( uVersion != HGCM_SAVED_STATE_VERSION + && uVersion != HGCM_SAVED_STATE_VERSION_V2) + return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; + Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); + + AssertReturn(pThis->pVMMDev, VERR_INTERNAL_ERROR_2); + Console::SafeVMPtrQuiet ptrVM(pThis->pVMMDev->mParent); + AssertReturn(ptrVM.isOk(), VERR_INTERNAL_ERROR_3); + return HGCMHostLoadState(pSSM, ptrVM.vtable(), uVersion); +} + +int VMMDev::hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName) +{ + if (!hgcmIsActive()) + return VERR_INVALID_STATE; + + /** @todo Construct all the services in the VMMDev::drvConstruct()!! */ + Assert( (mpDrv && mpDrv->pHGCMPort) + || !strcmp(pszServiceLibrary, "VBoxHostChannel") + || !strcmp(pszServiceLibrary, "VBoxSharedClipboard") + || !strcmp(pszServiceLibrary, "VBoxDragAndDropSvc") + || !strcmp(pszServiceLibrary, "VBoxGuestPropSvc") + || !strcmp(pszServiceLibrary, "VBoxSharedCrOpenGL") + ); + Console::SafeVMPtrQuiet ptrVM(mParent); + return HGCMHostLoad(pszServiceLibrary, pszServiceName, ptrVM.rawUVM(), ptrVM.vtable(), mpDrv ? mpDrv->pHGCMPort : NULL); +} + +int VMMDev::hgcmHostCall(const char *pszServiceName, uint32_t u32Function, + uint32_t cParms, PVBOXHGCMSVCPARM paParms) +{ + if (!hgcmIsActive()) + return VERR_INVALID_STATE; + return HGCMHostCall(pszServiceName, u32Function, cParms, paParms); +} + +/** + * Used by Console::i_powerDown to shut down the services before the VM is destroyed. + */ +void VMMDev::hgcmShutdown(bool fUvmIsInvalid /*= false*/) +{ +#ifdef VBOX_WITH_GUEST_PROPS + if (mpDrv && mpDrv->hHgcmSvcExtGstProps) + { + HGCMHostUnregisterServiceExtension(mpDrv->hHgcmSvcExtGstProps); + mpDrv->hHgcmSvcExtGstProps = NULL; + } +#endif + +#ifdef VBOX_WITH_GUEST_CONTROL + if (mpDrv && mpDrv->hHgcmSvcExtGstCtrl) + { + HGCMHostUnregisterServiceExtension(mpDrv->hHgcmSvcExtGstCtrl); + mpDrv->hHgcmSvcExtGstCtrl = NULL; + } +#endif + + if (ASMAtomicCmpXchgBool(&m_fHGCMActive, false, true)) + HGCMHostShutdown(fUvmIsInvalid); +} + +#endif /* HGCM */ + + +/** + * @interface_method_impl{PDMIBASE,pfnQueryInterface} + */ +DECLCALLBACK(void *) VMMDev::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID) +{ + PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface); + PDRVMAINVMMDEV pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); + + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVCONNECTOR, &pDrv->Connector); +#ifdef VBOX_WITH_HGCM + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMCONNECTOR, &pDrv->HGCMConnector); +#endif + return NULL; +} + +/** + * @interface_method_impl{PDMDRVREG,pfnSuspend} + */ +/*static*/ DECLCALLBACK(void) VMMDev::drvSuspend(PPDMDRVINS pDrvIns) +{ + RT_NOREF(pDrvIns); +#ifdef VBOX_WITH_HGCM + HGCMBroadcastEvent(HGCMNOTIFYEVENT_SUSPEND); +#endif +} + +/** + * @interface_method_impl{PDMDRVREG,pfnResume} + */ +/*static*/ DECLCALLBACK(void) VMMDev::drvResume(PPDMDRVINS pDrvIns) +{ + RT_NOREF(pDrvIns); +#ifdef VBOX_WITH_HGCM + HGCMBroadcastEvent(HGCMNOTIFYEVENT_RESUME); +#endif +} + +/** + * @interface_method_impl{PDMDRVREG,pfnPowerOff} + */ +/*static*/ DECLCALLBACK(void) VMMDev::drvPowerOff(PPDMDRVINS pDrvIns) +{ + RT_NOREF(pDrvIns); +#ifdef VBOX_WITH_HGCM + HGCMBroadcastEvent(HGCMNOTIFYEVENT_POWER_ON); +#endif +} + +/** + * @interface_method_impl{PDMDRVREG,pfnPowerOn} + */ +/*static*/ DECLCALLBACK(void) VMMDev::drvPowerOn(PPDMDRVINS pDrvIns) +{ + RT_NOREF(pDrvIns); +#ifdef VBOX_WITH_HGCM + HGCMBroadcastEvent(HGCMNOTIFYEVENT_POWER_ON); +#endif +} + +/** + * @interface_method_impl{PDMDRVREG,pfnReset} + */ +DECLCALLBACK(void) VMMDev::drvReset(PPDMDRVINS pDrvIns) +{ + RT_NOREF(pDrvIns); + LogFlow(("VMMDev::drvReset: iInstance=%d\n", pDrvIns->iInstance)); +#ifdef VBOX_WITH_HGCM + HGCMHostReset(false /*fForShutdown*/); +#endif +} + +/** + * @interface_method_impl{PDMDRVREG,pfnDestruct} + */ +DECLCALLBACK(void) VMMDev::drvDestruct(PPDMDRVINS pDrvIns) +{ + PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); + LogFlow(("VMMDev::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); + +#ifdef VBOX_WITH_GUEST_PROPS + if (pThis->hHgcmSvcExtGstProps) + { + HGCMHostUnregisterServiceExtension(pThis->hHgcmSvcExtGstProps); + pThis->hHgcmSvcExtGstProps = NULL; + } +#endif + +#ifdef VBOX_WITH_GUEST_CONTROL + if (pThis->hHgcmSvcExtGstCtrl) + { + HGCMHostUnregisterServiceExtension(pThis->hHgcmSvcExtGstCtrl); + pThis->hHgcmSvcExtGstCtrl = NULL; + } +#endif + + if (pThis->pVMMDev) + { +#ifdef VBOX_WITH_HGCM + /* When VM construction goes wrong, we prefer shutting down HGCM here + while pUVM is still valid, rather than in ~VMMDev. */ + if (ASMAtomicCmpXchgBool(&pThis->pVMMDev->m_fHGCMActive, false, true)) + HGCMHostShutdown(); +#endif + pThis->pVMMDev->mpDrv = NULL; + } +} + +#ifdef VBOX_WITH_GUEST_PROPS + +/** + * Set an array of guest properties + */ +void VMMDev::i_guestPropSetMultiple(void *names, void *values, void *timestamps, void *flags) +{ + VBOXHGCMSVCPARM parms[4]; + + parms[0].type = VBOX_HGCM_SVC_PARM_PTR; + parms[0].u.pointer.addr = names; + parms[0].u.pointer.size = 0; /* We don't actually care. */ + parms[1].type = VBOX_HGCM_SVC_PARM_PTR; + parms[1].u.pointer.addr = values; + parms[1].u.pointer.size = 0; /* We don't actually care. */ + parms[2].type = VBOX_HGCM_SVC_PARM_PTR; + parms[2].u.pointer.addr = timestamps; + parms[2].u.pointer.size = 0; /* We don't actually care. */ + parms[3].type = VBOX_HGCM_SVC_PARM_PTR; + parms[3].u.pointer.addr = flags; + parms[3].u.pointer.size = 0; /* We don't actually care. */ + + hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROPS, 4, &parms[0]); +} + +/** + * Set a single guest property + */ +void VMMDev::i_guestPropSet(const char *pszName, const char *pszValue, const char *pszFlags) +{ + VBOXHGCMSVCPARM parms[4]; + + AssertPtrReturnVoid(pszName); + AssertPtrReturnVoid(pszValue); + AssertPtrReturnVoid(pszFlags); + parms[0].type = VBOX_HGCM_SVC_PARM_PTR; + parms[0].u.pointer.addr = (void *)pszName; + parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1; + parms[1].type = VBOX_HGCM_SVC_PARM_PTR; + parms[1].u.pointer.addr = (void *)pszValue; + parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1; + parms[2].type = VBOX_HGCM_SVC_PARM_PTR; + parms[2].u.pointer.addr = (void *)pszFlags; + parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1; + hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP, 3, &parms[0]); +} + +/** + * Set the global flags value by calling the service + * @returns the status returned by the call to the service + * + * @param pTable the service instance handle + * @param eFlags the flags to set + */ +int VMMDev::i_guestPropSetGlobalPropertyFlags(uint32_t fFlags) +{ + VBOXHGCMSVCPARM parm; + HGCMSvcSetU32(&parm, fFlags); + int vrc = hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS, 1, &parm); + if (RT_FAILURE(vrc)) + { + char szFlags[GUEST_PROP_MAX_FLAGS_LEN]; + if (RT_FAILURE(GuestPropWriteFlags(fFlags, szFlags))) + Log(("Failed to set the global flags.\n")); + else + Log(("Failed to set the global flags \"%s\".\n", szFlags)); + } + return vrc; +} + + +/** + * Set up the Guest Property service, populate it with properties read from + * the machine XML and set a couple of initial properties. + */ +int VMMDev::i_guestPropLoadAndConfigure() +{ + Assert(mpDrv); + ComObjPtr<Console> ptrConsole = this->mParent; + AssertReturn(ptrConsole.isNotNull(), VERR_INVALID_POINTER); + + /* + * Load the service + */ + int vrc = hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc"); + if (RT_FAILURE(vrc)) + { + LogRel(("VBoxGuestPropSvc is not available. vrc = %Rrc\n", vrc)); + return VINF_SUCCESS; /* That is not a fatal failure. */ + } + + /* + * Pull over the properties from the server. + */ + SafeArray<BSTR> namesOut; + SafeArray<BSTR> valuesOut; + SafeArray<LONG64> timestampsOut; + SafeArray<BSTR> flagsOut; + HRESULT hrc = ptrConsole->i_pullGuestProperties(ComSafeArrayAsOutParam(namesOut), + ComSafeArrayAsOutParam(valuesOut), + ComSafeArrayAsOutParam(timestampsOut), + ComSafeArrayAsOutParam(flagsOut)); + AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR); + size_t const cProps = namesOut.size(); + size_t const cAlloc = cProps + 1; + AssertLogRelReturn(valuesOut.size() == cProps, VERR_INTERNAL_ERROR_2); + AssertLogRelReturn(timestampsOut.size() == cProps, VERR_INTERNAL_ERROR_3); + AssertLogRelReturn(flagsOut.size() == cProps, VERR_INTERNAL_ERROR_4); + + char szEmpty[] = ""; + char **papszNames = (char **)RTMemTmpAllocZ(sizeof(char *) * cAlloc); + char **papszValues = (char **)RTMemTmpAllocZ(sizeof(char *) * cAlloc); + LONG64 *pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc); + char **papszFlags = (char **)RTMemTmpAllocZ(sizeof(char *) * cAlloc); + if (papszNames && papszValues && pai64Timestamps && papszFlags) + { + for (unsigned i = 0; RT_SUCCESS(vrc) && i < cProps; ++i) + { + AssertPtrBreakStmt(namesOut[i], vrc = VERR_INVALID_PARAMETER); + vrc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]); + if (RT_FAILURE(vrc)) + break; + if (valuesOut[i]) + vrc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]); + else + papszValues[i] = szEmpty; + if (RT_FAILURE(vrc)) + break; + pai64Timestamps[i] = timestampsOut[i]; + if (flagsOut[i]) + vrc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]); + else + papszFlags[i] = szEmpty; + } + if (RT_SUCCESS(vrc)) + i_guestPropSetMultiple((void *)papszNames, (void *)papszValues, (void *)pai64Timestamps, (void *)papszFlags); + for (unsigned i = 0; i < cProps; ++i) + { + RTStrFree(papszNames[i]); + if (valuesOut[i]) + RTStrFree(papszValues[i]); + if (flagsOut[i]) + RTStrFree(papszFlags[i]); + } + } + else + vrc = VERR_NO_MEMORY; + RTMemTmpFree(papszNames); + RTMemTmpFree(papszValues); + RTMemTmpFree(pai64Timestamps); + RTMemTmpFree(papszFlags); + AssertRCReturn(vrc, vrc); + + /* + * Register the host notification callback + */ + HGCMHostRegisterServiceExtension(&mpDrv->hHgcmSvcExtGstProps, "VBoxGuestPropSvc", Console::i_doGuestPropNotification, ptrConsole.m_p); + +# ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST + vrc = i_guestPropSetGlobalPropertyFlags(GUEST_PROP_F_RDONLYGUEST); + AssertRCReturn(vrc, vrc); +# endif + + Log(("Set VBoxGuestPropSvc property store\n")); + return VINF_SUCCESS; +} + +#endif /* VBOX_WITH_GUEST_PROPS */ + +/** + * @interface_method_impl{PDMDRVREG,pfnConstruct} + */ +DECLCALLBACK(int) VMMDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) +{ + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + RT_NOREF(fFlags, pCfg); + PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); + LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance)); + + /* + * Validate configuration. + */ + PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", ""); + AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, + ("Configuration error: Not possible to attach anything to this driver!\n"), + VERR_PDM_DRVINS_NO_ATTACH); + + /* + * IBase. + */ + pDrvIns->IBase.pfnQueryInterface = VMMDev::drvQueryInterface; + + pThis->Connector.pfnUpdateGuestStatus = vmmdevUpdateGuestStatus; + pThis->Connector.pfnUpdateGuestUserState = vmmdevUpdateGuestUserState; + pThis->Connector.pfnUpdateGuestInfo = vmmdevUpdateGuestInfo; + pThis->Connector.pfnUpdateGuestInfo2 = vmmdevUpdateGuestInfo2; + pThis->Connector.pfnUpdateGuestCapabilities = vmmdevUpdateGuestCapabilities; + pThis->Connector.pfnUpdateMouseCapabilities = vmmdevUpdateMouseCapabilities; + pThis->Connector.pfnUpdatePointerShape = vmmdevUpdatePointerShape; + pThis->Connector.pfnVideoAccelEnable = iface_VideoAccelEnable; + pThis->Connector.pfnVideoAccelFlush = iface_VideoAccelFlush; + pThis->Connector.pfnVideoModeSupported = vmmdevVideoModeSupported; + pThis->Connector.pfnGetHeightReduction = vmmdevGetHeightReduction; + pThis->Connector.pfnSetCredentialsJudgementResult = vmmdevSetCredentialsJudgementResult; + pThis->Connector.pfnSetVisibleRegion = vmmdevSetVisibleRegion; + pThis->Connector.pfnUpdateMonitorPositions = vmmdevUpdateMonitorPositions; + pThis->Connector.pfnQueryVisibleRegion = vmmdevQueryVisibleRegion; + pThis->Connector.pfnReportStatistics = vmmdevReportStatistics; + pThis->Connector.pfnQueryStatisticsInterval = vmmdevQueryStatisticsInterval; + pThis->Connector.pfnQueryBalloonSize = vmmdevQueryBalloonSize; + pThis->Connector.pfnIsPageFusionEnabled = vmmdevIsPageFusionEnabled; + +#ifdef VBOX_WITH_HGCM + pThis->HGCMConnector.pfnConnect = iface_hgcmConnect; + pThis->HGCMConnector.pfnDisconnect = iface_hgcmDisconnect; + pThis->HGCMConnector.pfnCall = iface_hgcmCall; + pThis->HGCMConnector.pfnCancelled = iface_hgcmCancelled; +#endif + + /* + * Get the IVMMDevPort interface of the above driver/device. + */ + pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIVMMDEVPORT); + AssertMsgReturn(pThis->pUpPort, ("Configuration error: No VMMDev port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); + +#ifdef VBOX_WITH_HGCM + pThis->pHGCMPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHGCMPORT); + AssertMsgReturn(pThis->pHGCMPort, ("Configuration error: No HGCM port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); +#endif + + /* + * Get the Console object pointer and update the mpDrv member. + */ + com::Guid uuid(VMMDEV_OID); + pThis->pVMMDev = (VMMDev *)PDMDrvHlpQueryGenericUserObject(pDrvIns, uuid.raw()); + if (!pThis->pVMMDev) + { + AssertMsgFailed(("Configuration error: No/bad VMMDev object!\n")); + return VERR_NOT_FOUND; + } + pThis->pVMMDev->mpDrv = pThis; + + int vrc = VINF_SUCCESS; +#ifdef VBOX_WITH_HGCM + /* + * Load & configure the shared folders service. + */ + vrc = pThis->pVMMDev->hgcmLoadService(VBOXSHAREDFOLDERS_DLL, "VBoxSharedFolders"); + pThis->pVMMDev->fSharedFolderActive = RT_SUCCESS(vrc); + if (RT_SUCCESS(vrc)) + { + PPDMLED pLed; + PPDMILEDPORTS pLedPort; + + LogRel(("Shared Folders service loaded\n")); + pLedPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS); + AssertMsgReturn(pLedPort, ("Configuration error: No LED port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); + vrc = pLedPort->pfnQueryStatusLed(pLedPort, 0, &pLed); + if (RT_SUCCESS(vrc) && pLed) + { + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pLed; + parm.u.pointer.size = sizeof(*pLed); + + vrc = HGCMHostCall("VBoxSharedFolders", SHFL_FN_SET_STATUS_LED, 1, &parm); + } + else + AssertMsgFailed(("pfnQueryStatusLed failed with %Rrc (pLed=%x)\n", vrc, pLed)); + } + else + LogRel(("Failed to load Shared Folders service %Rrc\n", vrc)); + + + /* + * Load and configure the guest control service. + */ +# ifdef VBOX_WITH_GUEST_CONTROL + vrc = pThis->pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc"); + if (RT_SUCCESS(vrc)) + { + vrc = HGCMHostRegisterServiceExtension(&pThis->hHgcmSvcExtGstCtrl, "VBoxGuestControlSvc", + &Guest::i_notifyCtrlDispatcher, + pThis->pVMMDev->mParent->i_getGuest()); + if (RT_SUCCESS(vrc)) + LogRel(("Guest Control service loaded\n")); + else + LogRel(("Warning: Cannot register VBoxGuestControlSvc extension! vrc=%Rrc\n", vrc)); + } + else + LogRel(("Warning!: Failed to load the Guest Control Service! %Rrc\n", vrc)); +# endif /* VBOX_WITH_GUEST_CONTROL */ + + + /* + * Load and configure the guest properties service. + */ +# ifdef VBOX_WITH_GUEST_PROPS + vrc = pThis->pVMMDev->i_guestPropLoadAndConfigure(); + AssertLogRelRCReturn(vrc, vrc); +# endif + + + /* + * The HGCM saved state. + */ + vrc = PDMDrvHlpSSMRegisterEx(pDrvIns, HGCM_SAVED_STATE_VERSION, 4096 /* bad guess */, + NULL, NULL, NULL, + NULL, VMMDev::hgcmSave, NULL, + NULL, VMMDev::hgcmLoad, NULL); + if (RT_FAILURE(vrc)) + return vrc; + +#endif /* VBOX_WITH_HGCM */ + + return VINF_SUCCESS; +} + + +/** + * VMMDevice driver registration record. + */ +const PDMDRVREG VMMDev::DrvReg = +{ + /* u32Version */ + PDM_DRVREG_VERSION, + /* szName */ + "HGCM", + /* szRCMod */ + "", + /* szR0Mod */ + "", + /* pszDescription */ + "Main VMMDev driver (Main as in the API).", + /* fFlags */ + PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT, + /* fClass. */ + PDM_DRVREG_CLASS_VMMDEV, + /* cMaxInstances */ + ~0U, + /* cbInstance */ + sizeof(DRVMAINVMMDEV), + /* pfnConstruct */ + VMMDev::drvConstruct, + /* pfnDestruct */ + VMMDev::drvDestruct, + /* pfnRelocate */ + NULL, + /* pfnIOCtl */ + NULL, + /* pfnPowerOn */ + VMMDev::drvPowerOn, + /* pfnReset */ + VMMDev::drvReset, + /* pfnSuspend */ + VMMDev::drvSuspend, + /* pfnResume */ + VMMDev::drvResume, + /* pfnAttach */ + NULL, + /* pfnDetach */ + NULL, + /* pfnPowerOff */ + VMMDev::drvPowerOff, + /* pfnSoftReset */ + NULL, + /* u32EndVersion */ + PDM_DRVREG_VERSION +}; +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ |