Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* $Id: VMMDev.cpp $ */
- /** @file
- * VMMDev - Guest <-> VMM/Host communication device.
- */
- /*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
- /** @page pg_vmmdev The VMM Device.
- *
- * The VMM device is a custom hardware device emulation for communicating with
- * the guest additions.
- *
- * Whenever host wants to inform guest about something an IRQ notification will
- * be raised.
- *
- * VMMDev PDM interface will contain the guest notification method.
- *
- * There is a 32 bit event mask which will be read by guest on an interrupt. A
- * non zero bit in the mask means that the specific event occurred and requires
- * processing on guest side.
- *
- * After reading the event mask guest must issue a generic request
- * AcknowlegdeEvents.
- *
- * IRQ line is set to 1 (request) if there are unprocessed events, that is the
- * event mask is not zero.
- *
- * After receiving an interrupt and checking event mask, the guest must process
- * events using the event specific mechanism.
- *
- * That is if mouse capabilities were changed, guest will use
- * VMMDev_GetMouseStatus generic request.
- *
- * Event mask is only a set of flags indicating that guest must proceed with a
- * procedure.
- *
- * Unsupported events are therefore ignored. The guest additions must inform
- * host which events they want to receive, to avoid unnecessary IRQ processing.
- * By default no events are signalled to guest.
- *
- * This seems to be fast method. It requires only one context switch for an
- * event processing.
- *
- *
- * @section sec_vmmdev_heartbeat Heartbeat
- *
- * The heartbeat is a feature to monitor whether the guest OS is hung or not.
- *
- * The main kernel component of the guest additions, VBoxGuest, sets up a timer
- * at a frequency returned by VMMDevReq_HeartbeatConfigure
- * (VMMDevReqHeartbeat::cNsInterval, VMMDEV::cNsHeartbeatInterval) and performs
- * a VMMDevReq_GuestHeartbeat request every time the timer ticks.
- *
- * The host side (VMMDev) arms a timer with a more distant deadline
- * (VMMDEV::cNsHeartbeatTimeout), twice cNsHeartbeatInterval by default. Each
- * time a VMMDevReq_GuestHeartbeat request comes in, the timer is rearmed with
- * the same relative deadline. So, as long as VMMDevReq_GuestHeartbeat comes
- * when they should, the host timer will never fire.
- *
- * When the timer fires, we consider the guest as hung / flatlined / dead.
- * Currently we only LogRel that, but it's easy to extend this with an event in
- * Main API.
- *
- * Should the guest reawaken at some later point, we LogRel that event and
- * continue as normal. Again something which would merit an API event.
- *
- */
- /*********************************************************************************************************************************
- * Header Files *
- *********************************************************************************************************************************/
- /* Enable dev_vmm Log3 statements to get IRQ-related logging. */
- #define LOG_GROUP LOG_GROUP_DEV_VMM
- #include <VBox/VMMDev.h>
- #include <VBox/vmm/mm.h>
- #include <VBox/log.h>
- #include <VBox/param.h>
- #include <iprt/path.h>
- #include <iprt/dir.h>
- #include <iprt/file.h>
- #include <VBox/vmm/pgm.h>
- #include <VBox/err.h>
- #include <VBox/vmm/vm.h> /* for VM_IS_EMT */
- #include <VBox/dbg.h>
- #include <VBox/version.h>
- #include <iprt/asm.h>
- #include <iprt/asm-amd64-x86.h>
- #include <iprt/assert.h>
- #include <iprt/buildconfig.h>
- #include <iprt/string.h>
- #include <iprt/time.h>
- #ifndef IN_RC
- # include <iprt/mem.h>
- #endif
- #ifdef IN_RING3
- # include <iprt/uuid.h>
- #endif
- #include "VMMDevState.h"
- #ifdef VBOX_WITH_HGCM
- # include "VMMDevHGCM.h"
- #endif
- #ifndef VBOX_WITHOUT_TESTING_FEATURES
- # include "VMMDevTesting.h"
- #endif
- /*********************************************************************************************************************************
- * Defined Constants And Macros *
- *********************************************************************************************************************************/
- #define VMMDEV_INTERFACE_VERSION_IS_1_03(s) \
- ( RT_HIWORD((s)->guestInfo.interfaceVersion) == 1 \
- && RT_LOWORD((s)->guestInfo.interfaceVersion) == 3 )
- #define VMMDEV_INTERFACE_VERSION_IS_OK(additionsVersion) \
- ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
- && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) )
- #define VMMDEV_INTERFACE_VERSION_IS_OLD(additionsVersion) \
- ( (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
- || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
- && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) ) )
- #define VMMDEV_INTERFACE_VERSION_IS_TOO_OLD(additionsVersion) \
- ( RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) )
- #define VMMDEV_INTERFACE_VERSION_IS_NEW(additionsVersion) \
- ( RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
- || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
- && RT_LOWORD(additionsVersion) > RT_LOWORD(VMMDEV_VERSION) ) )
- /** The saved state version. */
- #define VMMDEV_SAVED_STATE_VERSION VMMDEV_SAVED_STATE_VERSION_HEARTBEAT
- /** The saved state version with heartbeat state. */
- #define VMMDEV_SAVED_STATE_VERSION_HEARTBEAT 16
- /** The saved state version without heartbeat state. */
- #define VMMDEV_SAVED_STATE_VERSION_NO_HEARTBEAT 15
- /** The saved state version which is missing the guest facility statuses. */
- #define VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES 14
- /** The saved state version which is missing the guestInfo2 bits. */
- #define VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2 13
- /** The saved state version used by VirtualBox 3.0.
- * This doesn't have the config part. */
- #define VMMDEV_SAVED_STATE_VERSION_VBOX_30 11
- /** Default interval in nanoseconds between guest heartbeats.
- * Used when no HeartbeatInterval is set in CFGM and for setting
- * HB check timer if the guest's heartbeat frequency is less than 1Hz. */
- #define VMMDEV_HEARTBEAT_DEFAULT_INTERVAL (2U*RT_NS_1SEC_64)
- #ifndef VBOX_DEVICE_STRUCT_TESTCASE
- /* -=-=-=-=- Misc Helpers -=-=-=-=- */
- /**
- * Log information about the Guest Additions.
- *
- * @param pGuestInfo The information we've got from the Guest Additions driver.
- */
- static void vmmdevLogGuestOsInfo(VBoxGuestInfo *pGuestInfo)
- {
- const char *pszOs;
- switch (pGuestInfo->osType & ~VBOXOSTYPE_x64)
- {
- case VBOXOSTYPE_DOS: pszOs = "DOS"; break;
- case VBOXOSTYPE_Win31: pszOs = "Windows 3.1"; break;
- case VBOXOSTYPE_Win9x: pszOs = "Windows 9x"; break;
- case VBOXOSTYPE_Win95: pszOs = "Windows 95"; break;
- case VBOXOSTYPE_Win98: pszOs = "Windows 98"; break;
- case VBOXOSTYPE_WinMe: pszOs = "Windows Me"; break;
- case VBOXOSTYPE_WinNT: pszOs = "Windows NT"; break;
- case VBOXOSTYPE_WinNT4: pszOs = "Windows NT4"; break;
- case VBOXOSTYPE_Win2k: pszOs = "Windows 2k"; break;
- case VBOXOSTYPE_WinXP: pszOs = "Windows XP"; break;
- case VBOXOSTYPE_Win2k3: pszOs = "Windows 2k3"; break;
- case VBOXOSTYPE_WinVista: pszOs = "Windows Vista"; break;
- case VBOXOSTYPE_Win2k8: pszOs = "Windows 2k8"; break;
- case VBOXOSTYPE_Win7: pszOs = "Windows 7"; break;
- case VBOXOSTYPE_Win8: pszOs = "Windows 8"; break;
- case VBOXOSTYPE_Win2k12_x64 & ~VBOXOSTYPE_x64: pszOs = "Windows 2k12"; break;
- case VBOXOSTYPE_Win81: pszOs = "Windows 8.1"; break;
- case VBOXOSTYPE_Win10: pszOs = "Windows 10"; break;
- case VBOXOSTYPE_OS2: pszOs = "OS/2"; break;
- case VBOXOSTYPE_OS2Warp3: pszOs = "OS/2 Warp 3"; break;
- case VBOXOSTYPE_OS2Warp4: pszOs = "OS/2 Warp 4"; break;
- case VBOXOSTYPE_OS2Warp45: pszOs = "OS/2 Warp 4.5"; break;
- case VBOXOSTYPE_ECS: pszOs = "OS/2 ECS"; break;
- case VBOXOSTYPE_OS21x: pszOs = "OS/2 2.1x"; break;
- case VBOXOSTYPE_Linux: pszOs = "Linux"; break;
- case VBOXOSTYPE_Linux22: pszOs = "Linux 2.2"; break;
- case VBOXOSTYPE_Linux24: pszOs = "Linux 2.4"; break;
- case VBOXOSTYPE_Linux26: pszOs = "Linux >= 2.6"; break;
- case VBOXOSTYPE_ArchLinux: pszOs = "ArchLinux"; break;
- case VBOXOSTYPE_Debian: pszOs = "Debian"; break;
- case VBOXOSTYPE_OpenSUSE: pszOs = "openSUSE"; break;
- case VBOXOSTYPE_FedoraCore: pszOs = "Fedora"; break;
- case VBOXOSTYPE_Gentoo: pszOs = "Gentoo"; break;
- case VBOXOSTYPE_Mandriva: pszOs = "Mandriva"; break;
- case VBOXOSTYPE_RedHat: pszOs = "RedHat"; break;
- case VBOXOSTYPE_Turbolinux: pszOs = "TurboLinux"; break;
- case VBOXOSTYPE_Ubuntu: pszOs = "Ubuntu"; break;
- case VBOXOSTYPE_Xandros: pszOs = "Xandros"; break;
- case VBOXOSTYPE_Oracle: pszOs = "Oracle Linux"; break;
- case VBOXOSTYPE_FreeBSD: pszOs = "FreeBSD"; break;
- case VBOXOSTYPE_OpenBSD: pszOs = "OpenBSD"; break;
- case VBOXOSTYPE_NetBSD: pszOs = "NetBSD"; break;
- case VBOXOSTYPE_Netware: pszOs = "Netware"; break;
- case VBOXOSTYPE_Solaris: pszOs = "Solaris"; break;
- case VBOXOSTYPE_OpenSolaris: pszOs = "OpenSolaris"; break;
- case VBOXOSTYPE_Solaris11_x64 & ~VBOXOSTYPE_x64: pszOs = "Solaris 11"; break;
- case VBOXOSTYPE_MacOS: pszOs = "Mac OS X"; break;
- case VBOXOSTYPE_MacOS106: pszOs = "Mac OS X 10.6"; break;
- case VBOXOSTYPE_MacOS107_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.7"; break;
- case VBOXOSTYPE_MacOS108_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.8"; break;
- case VBOXOSTYPE_MacOS109_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.9"; break;
- case VBOXOSTYPE_MacOS1010_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.10"; break;
- case VBOXOSTYPE_MacOS1011_x64 & ~VBOXOSTYPE_x64: pszOs = "Mac OS X 10.11"; break;
- case VBOXOSTYPE_Haiku: pszOs = "Haiku"; break;
- default: pszOs = "unknown"; break;
- }
- LogRel(("VMMDev: Guest Additions information report: Interface = 0x%08X osType = 0x%08X (%s, %u-bit)\n",
- pGuestInfo->interfaceVersion, pGuestInfo->osType, pszOs,
- pGuestInfo->osType & VBOXOSTYPE_x64 ? 64 : 32));
- }
- /**
- * Sets the IRQ (raise it or lower it) for 1.03 additions.
- *
- * @param pThis The VMMDev state.
- * @thread Any.
- * @remarks Must be called owning the critical section.
- */
- static void vmmdevSetIRQ_Legacy(PVMMDEV pThis)
- {
- if (pThis->fu32AdditionsOk)
- {
- /* Filter unsupported events */
- uint32_t fEvents = pThis->u32HostEventFlags & pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask;
- Log(("vmmdevSetIRQ: fEvents=%#010x, u32HostEventFlags=%#010x, u32GuestEventMask=%#010x.\n",
- fEvents, pThis->u32HostEventFlags, pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask));
- /* Move event flags to VMMDev RAM */
- pThis->pVMMDevRAMR3->V.V1_03.u32HostEvents = fEvents;
- uint32_t uIRQLevel = 0;
- if (fEvents)
- {
- /* Clear host flags which will be delivered to guest. */
- pThis->u32HostEventFlags &= ~fEvents;
- Log(("vmmdevSetIRQ: u32HostEventFlags=%#010x\n", pThis->u32HostEventFlags));
- uIRQLevel = 1;
- }
- /* Set IRQ level for pin 0 (see NoWait comment in vmmdevMaybeSetIRQ). */
- /** @todo make IRQ pin configurable, at least a symbolic constant */
- PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, uIRQLevel);
- Log(("vmmdevSetIRQ: IRQ set %d\n", uIRQLevel));
- }
- else
- Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
- }
- /**
- * Sets the IRQ if there are events to be delivered.
- *
- * @param pThis The VMMDev state.
- * @thread Any.
- * @remarks Must be called owning the critical section.
- */
- static void vmmdevMaybeSetIRQ(PVMMDEV pThis)
- {
- Log3(("vmmdevMaybeSetIRQ: u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
- pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
- if (pThis->u32HostEventFlags & pThis->u32GuestFilterMask)
- {
- /*
- * Note! No need to wait for the IRQs to be set (if we're not luck
- * with the locks, etc). It is a notification about something,
- * which has already happened.
- */
- pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = true;
- PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 1);
- Log3(("vmmdevMaybeSetIRQ: IRQ set.\n"));
- }
- }
- /**
- * Notifies the guest about new events (@a fAddEvents).
- *
- * @param pThis The VMMDev state.
- * @param fAddEvents New events to add.
- * @thread Any.
- * @remarks Must be called owning the critical section.
- */
- static void vmmdevNotifyGuestWorker(PVMMDEV pThis, uint32_t fAddEvents)
- {
- Log3(("vmmdevNotifyGuestWorker: fAddEvents=%#010x.\n", fAddEvents));
- Assert(PDMCritSectIsOwner(&pThis->CritSect));
- if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
- {
- Log3(("vmmdevNotifyGuestWorker: New additions detected.\n"));
- if (pThis->fu32AdditionsOk)
- {
- const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
- Log3(("vmmdevNotifyGuestWorker: fHadEvents=%d, u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
- fHadEvents, pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
- pThis->u32HostEventFlags |= fAddEvents;
- if (!fHadEvents)
- vmmdevMaybeSetIRQ(pThis);
- }
- else
- {
- pThis->u32HostEventFlags |= fAddEvents;
- Log(("vmmdevNotifyGuestWorker: IRQ is not generated, guest has not yet reported to us.\n"));
- }
- }
- else
- {
- Log3(("vmmdevNotifyGuestWorker: Old additions detected.\n"));
- pThis->u32HostEventFlags |= fAddEvents;
- vmmdevSetIRQ_Legacy(pThis);
- }
- }
- /* -=-=-=-=- Interfaces shared with VMMDevHGCM.cpp -=-=-=-=- */
- /**
- * Notifies the guest about new events (@a fAddEvents).
- *
- * This is used by VMMDev.cpp as well as VMMDevHGCM.cpp.
- *
- * @param pThis The VMMDev state.
- * @param fAddEvents New events to add.
- * @thread Any.
- */
- void VMMDevNotifyGuest(PVMMDEV pThis, uint32_t fAddEvents)
- {
- Log3(("VMMDevNotifyGuest: fAddEvents=%#010x\n", fAddEvents));
- /*
- * Only notify the VM when it's running.
- */
- VMSTATE enmVMState = PDMDevHlpVMState(pThis->pDevIns);
- /** @todo r=bird: Shouldn't there be more states here? Wouldn't we drop
- * notifications now when we're in the process of suspending or
- * similar? */
- if ( enmVMState == VMSTATE_RUNNING
- || enmVMState == VMSTATE_RUNNING_LS)
- {
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- vmmdevNotifyGuestWorker(pThis, fAddEvents);
- PDMCritSectLeave(&pThis->CritSect);
- }
- }
- /**
- * Code shared by VMMDevReq_CtlGuestFilterMask and HGCM for controlling the
- * events the guest are interested in.
- *
- * @param pThis The VMMDev state.
- * @param fOrMask Events to add (VMMDEV_EVENT_XXX). Pass 0 for no
- * change.
- * @param fNotMask Events to remove (VMMDEV_EVENT_XXX). Pass 0 for no
- * change.
- *
- * @remarks When HGCM will automatically enable VMMDEV_EVENT_HGCM when the guest
- * starts submitting HGCM requests. Otherwise, the events are
- * controlled by the guest.
- */
- void VMMDevCtlSetGuestFilterMask(PVMMDEV pThis, uint32_t fOrMask, uint32_t fNotMask)
- {
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
- Log(("VMMDevCtlSetGuestFilterMask: fOrMask=%#010x, u32NotMask=%#010x, fHadEvents=%d.\n", fOrMask, fNotMask, fHadEvents));
- if (fHadEvents)
- {
- if (!pThis->fNewGuestFilterMask)
- pThis->u32NewGuestFilterMask = pThis->u32GuestFilterMask;
- pThis->u32NewGuestFilterMask |= fOrMask;
- pThis->u32NewGuestFilterMask &= ~fNotMask;
- pThis->fNewGuestFilterMask = true;
- }
- else
- {
- pThis->u32GuestFilterMask |= fOrMask;
- pThis->u32GuestFilterMask &= ~fNotMask;
- vmmdevMaybeSetIRQ(pThis);
- }
- PDMCritSectLeave(&pThis->CritSect);
- }
- /* -=-=-=-=- Request processing functions. -=-=-=-=- */
- /**
- * Handles VMMDevReq_ReportGuestInfo.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pRequestHeader The header of the request to handle.
- */
- static int vmmdevReqHandler_ReportGuestInfo(PVMMDEV pThis, VMMDevRequestHeader *pRequestHeader)
- {
- AssertMsgReturn(pRequestHeader->size == sizeof(VMMDevReportGuestInfo), ("%u\n", pRequestHeader->size), VERR_INVALID_PARAMETER);
- VBoxGuestInfo const *pInfo = &((VMMDevReportGuestInfo *)pRequestHeader)->guestInfo;
- if (memcmp(&pThis->guestInfo, pInfo, sizeof(*pInfo)) != 0)
- {
- /* Make a copy of supplied information. */
- pThis->guestInfo = *pInfo;
- /* Check additions interface version. */
- pThis->fu32AdditionsOk = VMMDEV_INTERFACE_VERSION_IS_OK(pThis->guestInfo.interfaceVersion);
- vmmdevLogGuestOsInfo(&pThis->guestInfo);
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
- pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
- }
- if (!pThis->fu32AdditionsOk)
- return VERR_VERSION_MISMATCH;
- /* Clear our IRQ in case it was high for whatever reason. */
- PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GuestHeartbeat.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- */
- static int vmmDevReqHandler_GuestHeartbeat(PVMMDEV pThis)
- {
- int rc;
- if (pThis->fHeartbeatActive)
- {
- uint64_t const nsNowTS = TMTimerGetNano(pThis->pFlatlinedTimer);
- if (!pThis->fFlatlined)
- { /* likely */ }
- else
- {
- LogRel(("VMMDev: GuestHeartBeat: Guest is alive (gone %'llu ns)\n", nsNowTS - pThis->nsLastHeartbeatTS));
- ASMAtomicWriteBool(&pThis->fFlatlined, false);
- }
- ASMAtomicWriteU64(&pThis->nsLastHeartbeatTS, nsNowTS);
- /* Postpone (or restart if we missed a beat) the timeout timer. */
- rc = TMTimerSetNano(pThis->pFlatlinedTimer, pThis->cNsHeartbeatTimeout);
- }
- else
- rc = VINF_SUCCESS;
- return rc;
- }
- /**
- * Timer that fires when where have been no heartbeats for a given time.
- *
- * @remarks Does not take the VMMDev critsect.
- */
- static DECLCALLBACK(void) vmmDevHeartbeatFlatlinedTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
- {
- RT_NOREF1(pDevIns);
- PVMMDEV pThis = (PVMMDEV)pvUser;
- if (pThis->fHeartbeatActive)
- {
- uint64_t cNsElapsed = TMTimerGetNano(pTimer) - pThis->nsLastHeartbeatTS;
- if ( !pThis->fFlatlined
- && cNsElapsed >= pThis->cNsHeartbeatInterval)
- {
- LogRel(("VMMDev: vmmDevHeartbeatFlatlinedTimer: Guest seems to be unresponsive. Last heartbeat received %RU64 seconds ago\n",
- cNsElapsed / RT_NS_1SEC));
- ASMAtomicWriteBool(&pThis->fFlatlined, true);
- }
- }
- }
- /**
- * Handles VMMDevReq_HeartbeatConfigure.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmDevReqHandler_HeartbeatConfigure(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReqHeartbeat), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
- VMMDevReqHeartbeat *pReq = (VMMDevReqHeartbeat *)pReqHdr;
- int rc;
- pReq->cNsInterval = pThis->cNsHeartbeatInterval;
- if (pReq->fEnabled != pThis->fHeartbeatActive)
- {
- ASMAtomicWriteBool(&pThis->fHeartbeatActive, pReq->fEnabled);
- if (pReq->fEnabled)
- {
- /*
- * Activate the heartbeat monitor.
- */
- pThis->nsLastHeartbeatTS = TMTimerGetNano(pThis->pFlatlinedTimer);
- rc = TMTimerSetNano(pThis->pFlatlinedTimer, pThis->cNsHeartbeatTimeout);
- if (RT_SUCCESS(rc))
- LogRel(("VMMDev: Heartbeat flatline timer set to trigger after %'RU64 ns\n", pThis->cNsHeartbeatTimeout));
- else
- LogRel(("VMMDev: Error starting flatline timer (heartbeat): %Rrc\n", rc));
- }
- else
- {
- /*
- * Deactivate the heartbeat monitor.
- */
- rc = TMTimerStop(pThis->pFlatlinedTimer);
- LogRel(("VMMDev: Heartbeat checking timer has been stopped (rc=%Rrc)\n", rc));
- }
- }
- else
- {
- LogRel(("VMMDev: vmmDevReqHandler_HeartbeatConfigure: No change (fHeartbeatActive=%RTbool).\n", pThis->fHeartbeatActive));
- rc = VINF_SUCCESS;
- }
- return rc;
- }
- /**
- * Validates a publisher tag.
- *
- * @returns true / false.
- * @param pszTag Tag to validate.
- */
- static bool vmmdevReqIsValidPublisherTag(const char *pszTag)
- {
- /* Note! This character set is also found in Config.kmk. */
- static char const s_szValidChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz()[]{}+-.,";
- while (*pszTag != '\0')
- {
- if (!strchr(s_szValidChars, *pszTag))
- return false;
- pszTag++;
- }
- return true;
- }
- /**
- * Validates a build tag.
- *
- * @returns true / false.
- * @param pszTag Tag to validate.
- */
- static bool vmmdevReqIsValidBuildTag(const char *pszTag)
- {
- int cchPrefix;
- if (!strncmp(pszTag, "RC", 2))
- cchPrefix = 2;
- else if (!strncmp(pszTag, "BETA", 4))
- cchPrefix = 4;
- else if (!strncmp(pszTag, "ALPHA", 5))
- cchPrefix = 5;
- else
- return false;
- if (pszTag[cchPrefix] == '\0')
- return true;
- uint8_t u8;
- int rc = RTStrToUInt8Full(&pszTag[cchPrefix], 10, &u8);
- return rc == VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_ReportGuestInfo2.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_ReportGuestInfo2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReportGuestInfo2), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
- VBoxGuestInfo2 const *pInfo2 = &((VMMDevReportGuestInfo2 *)pReqHdr)->guestInfo;
- LogRel(("VMMDev: Guest Additions information report: Version %d.%d.%d r%d '%.*s'\n",
- pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild,
- pInfo2->additionsRevision, sizeof(pInfo2->szName), pInfo2->szName));
- /* The interface was introduced in 3.2 and will definitely not be
- backported beyond 3.0 (bird). */
- AssertMsgReturn(pInfo2->additionsMajor >= 3,
- ("%u.%u.%u\n", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild),
- VERR_INVALID_PARAMETER);
- /* The version must fit in a full version compression. */
- uint32_t uFullVersion = VBOX_FULL_VERSION_MAKE(pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild);
- AssertMsgReturn( VBOX_FULL_VERSION_GET_MAJOR(uFullVersion) == pInfo2->additionsMajor
- && VBOX_FULL_VERSION_GET_MINOR(uFullVersion) == pInfo2->additionsMinor
- && VBOX_FULL_VERSION_GET_BUILD(uFullVersion) == pInfo2->additionsBuild,
- ("%u.%u.%u\n", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild),
- VERR_OUT_OF_RANGE);
- /*
- * Validate the name.
- * Be less strict towards older additions (< v4.1.50).
- */
- AssertCompile(sizeof(pThis->guestInfo2.szName) == sizeof(pInfo2->szName));
- AssertReturn(RTStrEnd(pInfo2->szName, sizeof(pInfo2->szName)) != NULL, VERR_INVALID_PARAMETER);
- const char *pszName = pInfo2->szName;
- /* The version number which shouldn't be there. */
- char szTmp[sizeof(pInfo2->szName)];
- size_t cchStart = RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild);
- AssertMsgReturn(!strncmp(pszName, szTmp, cchStart), ("%s != %s\n", pszName, szTmp), VERR_INVALID_PARAMETER);
- pszName += cchStart;
- /* Now we can either have nothing or a build tag or/and a publisher tag. */
- if (*pszName != '\0')
- {
- const char *pszRelaxedName = "";
- bool const fStrict = pInfo2->additionsMajor > 4
- || (pInfo2->additionsMajor == 4 && pInfo2->additionsMinor > 1)
- || (pInfo2->additionsMajor == 4 && pInfo2->additionsMinor == 1 && pInfo2->additionsBuild >= 50);
- bool fOk = false;
- if (*pszName == '_')
- {
- pszName++;
- strcpy(szTmp, pszName);
- char *pszTag2 = strchr(szTmp, '_');
- if (!pszTag2)
- {
- fOk = vmmdevReqIsValidBuildTag(szTmp)
- || vmmdevReqIsValidPublisherTag(szTmp);
- }
- else
- {
- *pszTag2++ = '\0';
- fOk = vmmdevReqIsValidBuildTag(szTmp);
- if (fOk)
- {
- fOk = vmmdevReqIsValidPublisherTag(pszTag2);
- if (!fOk)
- pszRelaxedName = szTmp;
- }
- }
- }
- if (!fOk)
- {
- AssertLogRelMsgReturn(!fStrict, ("%s", pszName), VERR_INVALID_PARAMETER);
- /* non-strict mode, just zap the extra stuff. */
- LogRel(("VMMDev: ReportGuestInfo2: Ignoring unparsable version name bits: '%s' -> '%s'.\n", pszName, pszRelaxedName));
- pszName = pszRelaxedName;
- }
- }
- /*
- * Save the info and tell Main or whoever is listening.
- */
- pThis->guestInfo2.uFullVersion = uFullVersion;
- pThis->guestInfo2.uRevision = pInfo2->additionsRevision;
- pThis->guestInfo2.fFeatures = pInfo2->additionsFeatures;
- strcpy(pThis->guestInfo2.szName, pszName);
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo2)
- pThis->pDrv->pfnUpdateGuestInfo2(pThis->pDrv, uFullVersion, pszName, pInfo2->additionsRevision, pInfo2->additionsFeatures);
- /* Clear our IRQ in case it was high for whatever reason. */
- PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
- return VINF_SUCCESS;
- }
- /**
- * Allocates a new facility status entry, initializing it to inactive.
- *
- * @returns Pointer to a facility status entry on success, NULL on failure
- * (table full).
- * @param pThis The VMMDev instance data.
- * @param enmFacility The facility type code.
- * @param fFixed This is set when allocating the standard entries
- * from the constructor.
- * @param pTimeSpecNow Optionally giving the entry timestamp to use (ctor).
- */
- static PVMMDEVFACILITYSTATUSENTRY
- vmmdevAllocFacilityStatusEntry(PVMMDEV pThis, VBoxGuestFacilityType enmFacility, bool fFixed, PCRTTIMESPEC pTimeSpecNow)
- {
- /* If full, expunge one inactive entry. */
- if (pThis->cFacilityStatuses == RT_ELEMENTS(pThis->aFacilityStatuses))
- {
- uint32_t i = pThis->cFacilityStatuses;
- while (i-- > 0)
- {
- if ( pThis->aFacilityStatuses[i].enmStatus == VBoxGuestFacilityStatus_Inactive
- && !pThis->aFacilityStatuses[i].fFixed)
- {
- pThis->cFacilityStatuses--;
- int cToMove = pThis->cFacilityStatuses - i;
- if (cToMove)
- memmove(&pThis->aFacilityStatuses[i], &pThis->aFacilityStatuses[i + 1],
- cToMove * sizeof(pThis->aFacilityStatuses[i]));
- RT_ZERO(pThis->aFacilityStatuses[pThis->cFacilityStatuses]);
- break;
- }
- }
- if (pThis->cFacilityStatuses == RT_ELEMENTS(pThis->aFacilityStatuses))
- return NULL;
- }
- /* Find location in array (it's sorted). */
- uint32_t i = pThis->cFacilityStatuses;
- while (i-- > 0)
- if ((uint32_t)pThis->aFacilityStatuses[i].enmFacility < (uint32_t)enmFacility)
- break;
- i++;
- /* Move. */
- int cToMove = pThis->cFacilityStatuses - i;
- if (cToMove > 0)
- memmove(&pThis->aFacilityStatuses[i + 1], &pThis->aFacilityStatuses[i],
- cToMove * sizeof(pThis->aFacilityStatuses[i]));
- pThis->cFacilityStatuses++;
- /* Initialize. */
- pThis->aFacilityStatuses[i].enmFacility = enmFacility;
- pThis->aFacilityStatuses[i].enmStatus = VBoxGuestFacilityStatus_Inactive;
- pThis->aFacilityStatuses[i].fFixed = fFixed;
- pThis->aFacilityStatuses[i].afPadding[0] = 0;
- pThis->aFacilityStatuses[i].afPadding[1] = 0;
- pThis->aFacilityStatuses[i].afPadding[2] = 0;
- pThis->aFacilityStatuses[i].fFlags = 0;
- if (pTimeSpecNow)
- pThis->aFacilityStatuses[i].TimeSpecTS = *pTimeSpecNow;
- else
- RTTimeSpecSetNano(&pThis->aFacilityStatuses[i].TimeSpecTS, 0);
- return &pThis->aFacilityStatuses[i];
- }
- /**
- * Gets a facility status entry, allocating a new one if not already present.
- *
- * @returns Pointer to a facility status entry on success, NULL on failure
- * (table full).
- * @param pThis The VMMDev instance data.
- * @param enmFacility The facility type code.
- */
- static PVMMDEVFACILITYSTATUSENTRY vmmdevGetFacilityStatusEntry(PVMMDEV pThis, VBoxGuestFacilityType enmFacility)
- {
- /** @todo change to binary search. */
- uint32_t i = pThis->cFacilityStatuses;
- while (i-- > 0)
- {
- if (pThis->aFacilityStatuses[i].enmFacility == enmFacility)
- return &pThis->aFacilityStatuses[i];
- if ((uint32_t)pThis->aFacilityStatuses[i].enmFacility < (uint32_t)enmFacility)
- break;
- }
- return vmmdevAllocFacilityStatusEntry(pThis, enmFacility, false /*fFixed*/, NULL);
- }
- /**
- * Handles VMMDevReq_ReportGuestStatus.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_ReportGuestStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- /*
- * Validate input.
- */
- AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReportGuestStatus), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
- VBoxGuestStatus *pStatus = &((VMMDevReportGuestStatus *)pReqHdr)->guestStatus;
- AssertMsgReturn( pStatus->facility > VBoxGuestFacilityType_Unknown
- && pStatus->facility <= VBoxGuestFacilityType_All,
- ("%d\n", pStatus->facility),
- VERR_INVALID_PARAMETER);
- AssertMsgReturn(pStatus->status == (VBoxGuestFacilityStatus)(uint16_t)pStatus->status,
- ("%#x (%u)\n", pStatus->status, pStatus->status),
- VERR_OUT_OF_RANGE);
- /*
- * Do the update.
- */
- RTTIMESPEC Now;
- RTTimeNow(&Now);
- if (pStatus->facility == VBoxGuestFacilityType_All)
- {
- uint32_t i = pThis->cFacilityStatuses;
- while (i-- > 0)
- {
- pThis->aFacilityStatuses[i].TimeSpecTS = Now;
- pThis->aFacilityStatuses[i].enmStatus = pStatus->status;
- pThis->aFacilityStatuses[i].fFlags = pStatus->flags;
- }
- }
- else
- {
- PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, pStatus->facility);
- if (!pEntry)
- {
- LogRelMax(10, ("VMMDev: Facility table is full - facility=%u status=%u\n", pStatus->facility, pStatus->status));
- return VERR_OUT_OF_RESOURCES;
- }
- pEntry->TimeSpecTS = Now;
- pEntry->enmStatus = pStatus->status;
- pEntry->fFlags = pStatus->flags;
- }
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestStatus)
- pThis->pDrv->pfnUpdateGuestStatus(pThis->pDrv, pStatus->facility, pStatus->status, pStatus->flags, &Now);
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_ReportGuestUserState.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_ReportGuestUserState(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- /*
- * Validate input.
- */
- VMMDevReportGuestUserState *pReq = (VMMDevReportGuestUserState *)pReqHdr;
- AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
- if ( pThis->pDrv
- && pThis->pDrv->pfnUpdateGuestUserState)
- {
- /* Play safe. */
- AssertReturn(pReq->header.size <= _2K, VERR_TOO_MUCH_DATA);
- AssertReturn(pReq->status.cbUser <= 256, VERR_TOO_MUCH_DATA);
- AssertReturn(pReq->status.cbDomain <= 256, VERR_TOO_MUCH_DATA);
- AssertReturn(pReq->status.cbDetails <= _1K, VERR_TOO_MUCH_DATA);
- /* pbDynamic marks the beginning of the struct's dynamically
- * allocated data area. */
- uint8_t *pbDynamic = (uint8_t *)&pReq->status.szUser;
- uint32_t cbLeft = pReqHdr->size - RT_OFFSETOF(VMMDevReportGuestUserState, status.szUser);
- /* The user. */
- AssertReturn(pReq->status.cbUser > 0, VERR_INVALID_PARAMETER); /* User name is required. */
- AssertReturn(pReq->status.cbUser <= cbLeft, VERR_INVALID_PARAMETER);
- const char *pszUser = (const char *)pbDynamic;
- AssertReturn(RTStrEnd(pszUser, pReq->status.cbUser), VERR_INVALID_PARAMETER);
- int rc = RTStrValidateEncoding(pszUser);
- AssertRCReturn(rc, rc);
- /* Advance to the next field. */
- pbDynamic += pReq->status.cbUser;
- cbLeft -= pReq->status.cbUser;
- /* pszDomain can be NULL. */
- AssertReturn(pReq->status.cbDomain <= cbLeft, VERR_INVALID_PARAMETER);
- const char *pszDomain = NULL;
- if (pReq->status.cbDomain)
- {
- pszDomain = (const char *)pbDynamic;
- AssertReturn(RTStrEnd(pszDomain, pReq->status.cbDomain), VERR_INVALID_PARAMETER);
- rc = RTStrValidateEncoding(pszDomain);
- AssertRCReturn(rc, rc);
- /* Advance to the next field. */
- pbDynamic += pReq->status.cbDomain;
- cbLeft -= pReq->status.cbDomain;
- }
- /* pbDetails can be NULL. */
- const uint8_t *pbDetails = NULL;
- AssertReturn(pReq->status.cbDetails <= cbLeft, VERR_INVALID_PARAMETER);
- if (pReq->status.cbDetails > 0)
- pbDetails = pbDynamic;
- pThis->pDrv->pfnUpdateGuestUserState(pThis->pDrv, pszUser, pszDomain, (uint32_t)pReq->status.state,
- pbDetails, pReq->status.cbDetails);
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_ReportGuestCapabilities.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_ReportGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqGuestCapabilities *pReq = (VMMDevReqGuestCapabilities *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* Enable VMMDEV_GUEST_SUPPORTS_GRAPHICS automatically for guests using the old
- * request to report their capabilities.
- */
- const uint32_t fu32Caps = pReq->caps | VMMDEV_GUEST_SUPPORTS_GRAPHICS;
- if (pThis->guestCaps != fu32Caps)
- {
- /* make a copy of supplied information */
- pThis->guestCaps = fu32Caps;
- LogRel(("VMMDev: Guest Additions capability report (legacy): (0x%x) seamless: %s, hostWindowMapping: %s, graphics: yes\n",
- fu32Caps,
- fu32Caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
- fu32Caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no"));
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
- pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, fu32Caps);
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_SetGuestCapabilities.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_SetGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqGuestCapabilities2 *pReq = (VMMDevReqGuestCapabilities2 *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- uint32_t fu32Caps = pThis->guestCaps;
- fu32Caps |= pReq->u32OrMask;
- fu32Caps &= ~pReq->u32NotMask;
- LogRel(("VMMDev: Guest Additions capability report: (%#x -> %#x) seamless: %s, hostWindowMapping: %s, graphics: %s\n",
- pThis->guestCaps, fu32Caps,
- fu32Caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
- fu32Caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
- fu32Caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
- pThis->guestCaps = fu32Caps;
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
- pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, fu32Caps);
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetMouseStatus.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- pReq->mouseFeatures = pThis->mouseCapabilities
- & VMMDEV_MOUSE_MASK;
- pReq->pointerXPos = pThis->mouseXAbs;
- pReq->pointerYPos = pThis->mouseYAbs;
- LogRel2(("VMMDev: vmmdevReqHandler_GetMouseStatus: mouseFeatures=%#x, xAbs=%d, yAbs=%d\n",
- pReq->mouseFeatures, pReq->pointerXPos, pReq->pointerYPos));
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_SetMouseStatus.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_SetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: mouseFeatures=%#x\n", pReq->mouseFeatures));
- bool fNotify = false;
- if ( (pReq->mouseFeatures & VMMDEV_MOUSE_NOTIFY_HOST_MASK)
- != ( pThis->mouseCapabilities
- & VMMDEV_MOUSE_NOTIFY_HOST_MASK))
- fNotify = true;
- pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
- pThis->mouseCapabilities |= (pReq->mouseFeatures & VMMDEV_MOUSE_GUEST_MASK);
- LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: New host capabilities: %#x\n", pThis->mouseCapabilities));
- /*
- * Notify connector if something changed.
- */
- if (fNotify)
- {
- LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: Notifying connector\n"));
- pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
- }
- return VINF_SUCCESS;
- }
- static int vmmdevVerifyPointerShape(VMMDevReqMousePointer *pReq)
- {
- /* Should be enough for most mouse pointers. */
- if (pReq->width > 8192 || pReq->height > 8192)
- return VERR_INVALID_PARAMETER;
- uint32_t cbShape = (pReq->width + 7) / 8 * pReq->height; /* size of the AND mask */
- cbShape = ((cbShape + 3) & ~3) + pReq->width * 4 * pReq->height; /* + gap + size of the XOR mask */
- if (RT_UOFFSETOF(VMMDevReqMousePointer, pointerData) + cbShape > pReq->header.size)
- return VERR_INVALID_PARAMETER;
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_SetPointerShape.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_SetPointerShape(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqMousePointer *pReq = (VMMDevReqMousePointer *)pReqHdr;
- if (pReq->header.size < sizeof(*pReq))
- {
- AssertMsg(pReq->header.size == 0x10028 && pReq->header.version == 10000, /* don't complain about legacy!!! */
- ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
- pReq->header.size, pReq->header.size, pReq->header.version));
- return VERR_INVALID_PARAMETER;
- }
- bool fVisible = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_VISIBLE);
- bool fAlpha = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_ALPHA);
- bool fShape = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_SHAPE);
- Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
- fVisible, fAlpha, fShape, pReq->width, pReq->height));
- if (pReq->header.size == sizeof(VMMDevReqMousePointer))
- {
- /* The guest did not provide the shape actually. */
- fShape = false;
- }
- /* forward call to driver */
- if (fShape)
- {
- int rc = vmmdevVerifyPointerShape(pReq);
- if (RT_FAILURE(rc))
- return rc;
- pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
- fVisible,
- fAlpha,
- pReq->xHot, pReq->yHot,
- pReq->width, pReq->height,
- pReq->pointerData);
- }
- else
- {
- pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
- fVisible,
- 0,
- 0, 0,
- 0, 0,
- NULL);
- }
- pThis->fHostCursorRequested = fVisible;
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetHostTime.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetHostTime(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqHostTime *pReq = (VMMDevReqHostTime *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- if (RT_LIKELY(!pThis->fGetHostTimeDisabled))
- {
- RTTIMESPEC now;
- pReq->time = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pThis->pDevIns, &now));
- return VINF_SUCCESS;
- }
- return VERR_NOT_SUPPORTED;
- }
- /**
- * Handles VMMDevReq_GetHypervisorInfo.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetHypervisorInfo(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- return PGMR3MappingsSize(PDMDevHlpGetVM(pThis->pDevIns), &pReq->hypervisorSize);
- }
- /**
- * Handles VMMDevReq_SetHypervisorInfo.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_SetHypervisorInfo(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- int rc;
- PVM pVM = PDMDevHlpGetVM(pThis->pDevIns);
- if (pReq->hypervisorStart == 0)
- rc = PGMR3MappingsUnfix(pVM);
- else
- {
- /* only if the client has queried the size before! */
- uint32_t cbMappings;
- rc = PGMR3MappingsSize(pVM, &cbMappings);
- if (RT_SUCCESS(rc) && pReq->hypervisorSize == cbMappings)
- {
- /* new reservation */
- rc = PGMR3MappingsFix(pVM, pReq->hypervisorStart, pReq->hypervisorSize);
- LogRel(("VMMDev: Guest reported fixed hypervisor window at 0%010x LB %#x (rc=%Rrc)\n",
- pReq->hypervisorStart, pReq->hypervisorSize, rc));
- }
- else if (RT_FAILURE(rc))
- rc = VERR_TRY_AGAIN;
- }
- return rc;
- }
- /**
- * Handles VMMDevReq_RegisterPatchMemory.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_RegisterPatchMemory(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- return VMMR3RegisterPatchMemory(PDMDevHlpGetVM(pThis->pDevIns), pReq->pPatchMem, pReq->cbPatchMem);
- }
- /**
- * Handles VMMDevReq_DeregisterPatchMemory.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_DeregisterPatchMemory(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- return VMMR3DeregisterPatchMemory(PDMDevHlpGetVM(pThis->pDevIns), pReq->pPatchMem, pReq->cbPatchMem);
- }
- /**
- * Handles VMMDevReq_SetPowerStatus.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_SetPowerStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevPowerStateRequest *pReq = (VMMDevPowerStateRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- switch (pReq->powerState)
- {
- case VMMDevPowerState_Pause:
- {
- LogRel(("VMMDev: Guest requests the VM to be suspended (paused)\n"));
- return PDMDevHlpVMSuspend(pThis->pDevIns);
- }
- case VMMDevPowerState_PowerOff:
- {
- LogRel(("VMMDev: Guest requests the VM to be turned off\n"));
- return PDMDevHlpVMPowerOff(pThis->pDevIns);
- }
- case VMMDevPowerState_SaveState:
- {
- if (true /*pThis->fAllowGuestToSaveState*/)
- {
- LogRel(("VMMDev: Guest requests the VM to be saved and powered off\n"));
- return PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
- }
- LogRel(("VMMDev: Guest requests the VM to be saved and powered off, declined\n"));
- return VERR_ACCESS_DENIED;
- }
- default:
- AssertMsgFailed(("VMMDev: Invalid power state request: %d\n", pReq->powerState));
- return VERR_INVALID_PARAMETER;
- }
- }
- /**
- * Handles VMMDevReq_GetDisplayChangeRequest
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- * @remarks Deprecated.
- */
- static int vmmdevReqHandler_GetDisplayChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevDisplayChangeRequest *pReq = (VMMDevDisplayChangeRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /**
- * @todo It looks like a multi-monitor guest which only uses
- * @c VMMDevReq_GetDisplayChangeRequest (not the *2 version) will get
- * into a @c VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST event loop if it tries
- * to acknowlege host requests for additional monitors. Should the loop
- * which checks for those requests be removed?
- */
- DISPLAYCHANGEREQUEST *pDispRequest = &pThis->displayChangeData.aRequests[0];
- if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
- {
- /* Current request has been read at least once. */
- pDispRequest->fPending = false;
- /* Check if there are more pending requests. */
- for (unsigned i = 1; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
- {
- if (pThis->displayChangeData.aRequests[i].fPending)
- {
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
- break;
- }
- }
- /* Remember which resolution the client has queried, subsequent reads
- * will return the same values. */
- pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
- pThis->displayChangeData.fGuestSentChangeEventAck = true;
- }
- if (pThis->displayChangeData.fGuestSentChangeEventAck)
- {
- pReq->xres = pDispRequest->lastReadDisplayChangeRequest.xres;
- pReq->yres = pDispRequest->lastReadDisplayChangeRequest.yres;
- pReq->bpp = pDispRequest->lastReadDisplayChangeRequest.bpp;
- }
- else
- {
- /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
- * read the last valid video mode hint. This happens when the guest X server
- * determines the initial mode. */
- pReq->xres = pDispRequest->displayChangeRequest.xres;
- pReq->yres = pDispRequest->displayChangeRequest.yres;
- pReq->bpp = pDispRequest->displayChangeRequest.bpp;
- }
- Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n", pReq->xres, pReq->yres, pReq->bpp));
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetDisplayChangeRequest2.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetDisplayChangeRequest2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevDisplayChangeRequest2 *pReq = (VMMDevDisplayChangeRequest2 *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- DISPLAYCHANGEREQUEST *pDispRequest = NULL;
- if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
- {
- /* Select a pending request to report. */
- unsigned i;
- for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
- {
- if (pThis->displayChangeData.aRequests[i].fPending)
- {
- pDispRequest = &pThis->displayChangeData.aRequests[i];
- /* Remember which request should be reported. */
- pThis->displayChangeData.iCurrentMonitor = i;
- Log3(("VMMDev: will report pending request for %u\n", i));
- break;
- }
- }
- /* Check if there are more pending requests. */
- i++;
- for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
- {
- if (pThis->displayChangeData.aRequests[i].fPending)
- {
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
- Log3(("VMMDev: another pending at %u\n", i));
- break;
- }
- }
- if (pDispRequest)
- {
- /* Current request has been read at least once. */
- pDispRequest->fPending = false;
- /* Remember which resolution the client has queried, subsequent reads
- * will return the same values. */
- pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
- pThis->displayChangeData.fGuestSentChangeEventAck = true;
- }
- else
- {
- Log3(("VMMDev: no pending request!!!\n"));
- }
- }
- if (!pDispRequest)
- {
- Log3(("VMMDev: default to %d\n", pThis->displayChangeData.iCurrentMonitor));
- pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
- }
- if (pThis->displayChangeData.fGuestSentChangeEventAck)
- {
- pReq->xres = pDispRequest->lastReadDisplayChangeRequest.xres;
- pReq->yres = pDispRequest->lastReadDisplayChangeRequest.yres;
- pReq->bpp = pDispRequest->lastReadDisplayChangeRequest.bpp;
- pReq->display = pDispRequest->lastReadDisplayChangeRequest.display;
- }
- else
- {
- /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
- * read the last valid video mode hint. This happens when the guest X server
- * determines the initial video mode. */
- pReq->xres = pDispRequest->displayChangeRequest.xres;
- pReq->yres = pDispRequest->displayChangeRequest.yres;
- pReq->bpp = pDispRequest->displayChangeRequest.bpp;
- pReq->display = pDispRequest->displayChangeRequest.display;
- }
- Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
- pReq->xres, pReq->yres, pReq->bpp, pReq->display));
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetDisplayChangeRequestEx.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetDisplayChangeRequestEx(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevDisplayChangeRequestEx *pReq = (VMMDevDisplayChangeRequestEx *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- DISPLAYCHANGEREQUEST *pDispRequest = NULL;
- if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
- {
- /* Select a pending request to report. */
- unsigned i;
- for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
- {
- if (pThis->displayChangeData.aRequests[i].fPending)
- {
- pDispRequest = &pThis->displayChangeData.aRequests[i];
- /* Remember which request should be reported. */
- pThis->displayChangeData.iCurrentMonitor = i;
- Log3(("VMMDev: will report pending request for %d\n",
- i));
- break;
- }
- }
- /* Check if there are more pending requests. */
- i++;
- for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
- {
- if (pThis->displayChangeData.aRequests[i].fPending)
- {
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
- Log3(("VMMDev: another pending at %d\n",
- i));
- break;
- }
- }
- if (pDispRequest)
- {
- /* Current request has been read at least once. */
- pDispRequest->fPending = false;
- /* Remember which resolution the client has queried, subsequent reads
- * will return the same values. */
- pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
- pThis->displayChangeData.fGuestSentChangeEventAck = true;
- }
- else
- {
- Log3(("VMMDev: no pending request!!!\n"));
- }
- }
- if (!pDispRequest)
- {
- Log3(("VMMDev: default to %d\n",
- pThis->displayChangeData.iCurrentMonitor));
- pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
- }
- if (pThis->displayChangeData.fGuestSentChangeEventAck)
- {
- pReq->xres = pDispRequest->lastReadDisplayChangeRequest.xres;
- pReq->yres = pDispRequest->lastReadDisplayChangeRequest.yres;
- pReq->bpp = pDispRequest->lastReadDisplayChangeRequest.bpp;
- pReq->display = pDispRequest->lastReadDisplayChangeRequest.display;
- pReq->cxOrigin = pDispRequest->lastReadDisplayChangeRequest.xOrigin;
- pReq->cyOrigin = pDispRequest->lastReadDisplayChangeRequest.yOrigin;
- pReq->fEnabled = pDispRequest->lastReadDisplayChangeRequest.fEnabled;
- pReq->fChangeOrigin = pDispRequest->lastReadDisplayChangeRequest.fChangeOrigin;
- }
- else
- {
- /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
- * read the last valid video mode hint. This happens when the guest X server
- * determines the initial video mode. */
- pReq->xres = pDispRequest->displayChangeRequest.xres;
- pReq->yres = pDispRequest->displayChangeRequest.yres;
- pReq->bpp = pDispRequest->displayChangeRequest.bpp;
- pReq->display = pDispRequest->displayChangeRequest.display;
- pReq->cxOrigin = pDispRequest->displayChangeRequest.xOrigin;
- pReq->cyOrigin = pDispRequest->displayChangeRequest.yOrigin;
- pReq->fEnabled = pDispRequest->displayChangeRequest.fEnabled;
- pReq->fChangeOrigin = pDispRequest->displayChangeRequest.fChangeOrigin;
- }
- Log(("VMMDevEx: returning display change request xres = %d, yres = %d, bpp = %d id %d xPos = %d, yPos = %d & Enabled=%d\n",
- pReq->xres, pReq->yres, pReq->bpp, pReq->display, pReq->cxOrigin, pReq->cyOrigin, pReq->fEnabled));
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_VideoModeSupported.
- *
- * Query whether the given video mode is supported.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_VideoModeSupported(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevVideoModeSupportedRequest *pReq = (VMMDevVideoModeSupportedRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* forward the call */
- return pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
- 0, /* primary screen. */
- pReq->width,
- pReq->height,
- pReq->bpp,
- &pReq->fSupported);
- }
- /**
- * Handles VMMDevReq_VideoModeSupported2.
- *
- * Query whether the given video mode is supported for a specific display
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_VideoModeSupported2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevVideoModeSupportedRequest2 *pReq = (VMMDevVideoModeSupportedRequest2 *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* forward the call */
- return pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
- pReq->display,
- pReq->width,
- pReq->height,
- pReq->bpp,
- &pReq->fSupported);
- }
- /**
- * Handles VMMDevReq_GetHeightReduction.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetHeightReduction(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevGetHeightReductionRequest *pReq = (VMMDevGetHeightReductionRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* forward the call */
- return pThis->pDrv->pfnGetHeightReduction(pThis->pDrv, &pReq->heightReduction);
- }
- /**
- * Handles VMMDevReq_AcknowledgeEvents.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_AcknowledgeEvents(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevEvents *pReq = (VMMDevEvents *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
- {
- if (pThis->fNewGuestFilterMask)
- {
- pThis->fNewGuestFilterMask = false;
- pThis->u32GuestFilterMask = pThis->u32NewGuestFilterMask;
- }
- pReq->events = pThis->u32HostEventFlags & pThis->u32GuestFilterMask;
- pThis->u32HostEventFlags &= ~pThis->u32GuestFilterMask;
- pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = false;
- PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
- }
- else
- vmmdevSetIRQ_Legacy(pThis);
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_CtlGuestFilterMask.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_CtlGuestFilterMask(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevCtlGuestFilterMask *pReq = (VMMDevCtlGuestFilterMask *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- LogRelFlow(("VMMDev: vmmdevReqHandler_CtlGuestFilterMask: OR mask: %#x, NOT mask: %#x\n", pReq->u32OrMask, pReq->u32NotMask));
- /* HGCM event notification is enabled by the VMMDev device
- * automatically when any HGCM command is issued. The guest
- * cannot disable these notifications. */
- VMMDevCtlSetGuestFilterMask(pThis, pReq->u32OrMask, pReq->u32NotMask & ~VMMDEV_EVENT_HGCM);
- return VINF_SUCCESS;
- }
- #ifdef VBOX_WITH_HGCM
- /**
- * Handles VMMDevReq_HGCMConnect.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- * @param GCPhysReqHdr The guest physical address of the request header.
- */
- static int vmmdevReqHandler_HGCMConnect(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
- {
- VMMDevHGCMConnect *pReq = (VMMDevHGCMConnect *)pReqHdr;
- AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this is >= ... */
- if (pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_HGCMConnect\n"));
- return vmmdevHGCMConnect(pThis, pReq, GCPhysReqHdr);
- }
- Log(("VMMDevReq_HGCMConnect: HGCM Connector is NULL!\n"));
- return VERR_NOT_SUPPORTED;
- }
- /**
- * Handles VMMDevReq_HGCMDisconnect.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- * @param GCPhysReqHdr The guest physical address of the request header.
- */
- static int vmmdevReqHandler_HGCMDisconnect(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
- {
- VMMDevHGCMDisconnect *pReq = (VMMDevHGCMDisconnect *)pReqHdr;
- AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
- if (pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
- return vmmdevHGCMDisconnect(pThis, pReq, GCPhysReqHdr);
- }
- Log(("VMMDevReq_VMMDevHGCMDisconnect: HGCM Connector is NULL!\n"));
- return VERR_NOT_SUPPORTED;
- }
- /**
- * Handles VMMDevReq_HGCMCall.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- * @param GCPhysReqHdr The guest physical address of the request header.
- */
- static int vmmdevReqHandler_HGCMCall(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
- {
- VMMDevHGCMCall *pReq = (VMMDevHGCMCall *)pReqHdr;
- AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER);
- if (pThis->pHGCMDrv)
- {
- Log2(("VMMDevReq_HGCMCall: sizeof(VMMDevHGCMRequest) = %04X\n", sizeof(VMMDevHGCMCall)));
- Log2(("%.*Rhxd\n", pReq->header.header.size, pReq));
- #ifdef VBOX_WITH_64_BITS_GUESTS
- bool f64Bits = (pReq->header.header.requestType == VMMDevReq_HGCMCall64);
- #else
- bool f64Bits = false;
- #endif /* VBOX_WITH_64_BITS_GUESTS */
- return vmmdevHGCMCall(pThis, pReq, pReq->header.header.size, GCPhysReqHdr, f64Bits);
- }
- Log(("VMMDevReq_HGCMCall: HGCM Connector is NULL!\n"));
- return VERR_NOT_SUPPORTED;
- }
- /**
- * Handles VMMDevReq_HGCMCancel.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- * @param GCPhysReqHdr The guest physical address of the request header.
- */
- static int vmmdevReqHandler_HGCMCancel(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
- {
- VMMDevHGCMCancel *pReq = (VMMDevHGCMCancel *)pReqHdr;
- AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
- if (pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_VMMDevHGCMCancel\n"));
- return vmmdevHGCMCancel(pThis, pReq, GCPhysReqHdr);
- }
- Log(("VMMDevReq_VMMDevHGCMCancel: HGCM Connector is NULL!\n"));
- return VERR_NOT_SUPPORTED;
- }
- /**
- * Handles VMMDevReq_HGCMCancel2.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_HGCMCancel2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevHGCMCancel2 *pReq = (VMMDevHGCMCancel2 *)pReqHdr;
- AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
- if (pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_HGCMCancel2\n"));
- return vmmdevHGCMCancel2(pThis, pReq->physReqToCancel);
- }
- Log(("VMMDevReq_HGCMConnect2: HGCM Connector is NULL!\n"));
- return VERR_NOT_SUPPORTED;
- }
- #endif /* VBOX_WITH_HGCM */
- /**
- * Handles VMMDevReq_VideoAccelEnable.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_VideoAccelEnable(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevVideoAccelEnable *pReq = (VMMDevVideoAccelEnable *)pReqHdr;
- AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
- if (!pThis->pDrv)
- {
- Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!\n"));
- return VERR_NOT_SUPPORTED;
- }
- if (pReq->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
- {
- /* The guest driver seems compiled with different headers. */
- LogRelMax(16,("VMMDevReq_VideoAccelEnable guest ring buffer size %#x, should be %#x!!\n", pReq->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
- return VERR_INVALID_PARAMETER;
- }
- /* The request is correct. */
- pReq->fu32Status |= VBVA_F_STATUS_ACCEPTED;
- LogFlow(("VMMDevReq_VideoAccelEnable pReq->u32Enable = %d\n", pReq->u32Enable));
- int rc = pReq->u32Enable
- ? pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, true, &pThis->pVMMDevRAMR3->vbvaMemory)
- : pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, false, NULL);
- if ( pReq->u32Enable
- && RT_SUCCESS(rc))
- {
- pReq->fu32Status |= VBVA_F_STATUS_ENABLED;
- /* Remember that guest successfully enabled acceleration.
- * We need to reestablish it on restoring the VM from saved state.
- */
- pThis->u32VideoAccelEnabled = 1;
- }
- else
- {
- /* The acceleration was not enabled. Remember that. */
- pThis->u32VideoAccelEnabled = 0;
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_VideoAccelFlush.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_VideoAccelFlush(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevVideoAccelFlush *pReq = (VMMDevVideoAccelFlush *)pReqHdr;
- AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
- if (!pThis->pDrv)
- {
- Log(("VMMDevReq_VideoAccelFlush: Connector is NULL!!!\n"));
- return VERR_NOT_SUPPORTED;
- }
- pThis->pDrv->pfnVideoAccelFlush(pThis->pDrv);
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_VideoSetVisibleRegion.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_VideoSetVisibleRegion(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevVideoSetVisibleRegion *pReq = (VMMDevVideoSetVisibleRegion *)pReqHdr;
- AssertMsgReturn(pReq->header.size + sizeof(RTRECT) >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- if (!pThis->pDrv)
- {
- Log(("VMMDevReq_VideoSetVisibleRegion: Connector is NULL!!!\n"));
- return VERR_NOT_SUPPORTED;
- }
- if ( pReq->cRect > _1M /* restrict to sane range */
- || pReq->header.size != sizeof(VMMDevVideoSetVisibleRegion) + pReq->cRect * sizeof(RTRECT) - sizeof(RTRECT))
- {
- Log(("VMMDevReq_VideoSetVisibleRegion: cRects=%#x doesn't match size=%#x or is out of bounds\n",
- pReq->cRect, pReq->header.size));
- return VERR_INVALID_PARAMETER;
- }
- Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", pReq->cRect));
- /* forward the call */
- return pThis->pDrv->pfnSetVisibleRegion(pThis->pDrv, pReq->cRect, &pReq->Rect);
- }
- /**
- * Handles VMMDevReq_GetSeamlessChangeRequest.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetSeamlessChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevSeamlessChangeRequest *pReq = (VMMDevSeamlessChangeRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* just pass on the information */
- Log(("VMMDev: returning seamless change request mode=%d\n", pThis->fSeamlessEnabled));
- if (pThis->fSeamlessEnabled)
- pReq->mode = VMMDev_Seamless_Visible_Region;
- else
- pReq->mode = VMMDev_Seamless_Disabled;
- if (pReq->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
- {
- /* Remember which mode the client has queried. */
- pThis->fLastSeamlessEnabled = pThis->fSeamlessEnabled;
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetVRDPChangeRequest.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetVRDPChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevVRDPChangeRequest *pReq = (VMMDevVRDPChangeRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* just pass on the information */
- Log(("VMMDev: returning VRDP status %d level %d\n", pThis->fVRDPEnabled, pThis->uVRDPExperienceLevel));
- pReq->u8VRDPActive = pThis->fVRDPEnabled;
- pReq->u32VRDPExperienceLevel = pThis->uVRDPExperienceLevel;
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetMemBalloonChangeRequest.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetMemBalloonChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevGetMemBalloonChangeRequest *pReq = (VMMDevGetMemBalloonChangeRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* just pass on the information */
- Log(("VMMDev: returning memory balloon size =%d\n", pThis->cMbMemoryBalloon));
- pReq->cBalloonChunks = pThis->cMbMemoryBalloon;
- pReq->cPhysMemChunks = pThis->cbGuestRAM / (uint64_t)_1M;
- if (pReq->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
- {
- /* Remember which mode the client has queried. */
- pThis->cMbMemoryBalloonLast = pThis->cMbMemoryBalloon;
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_ChangeMemBalloon.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_ChangeMemBalloon(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevChangeMemBalloon *pReq = (VMMDevChangeMemBalloon *)pReqHdr;
- AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- AssertMsgReturn(pReq->cPages == VMMDEV_MEMORY_BALLOON_CHUNK_PAGES, ("%u\n", pReq->cPages), VERR_INVALID_PARAMETER);
- AssertMsgReturn(pReq->header.size == (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[pReq->cPages]),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- Log(("VMMDevReq_ChangeMemBalloon\n"));
- int rc = PGMR3PhysChangeMemBalloon(PDMDevHlpGetVM(pThis->pDevIns), !!pReq->fInflate, pReq->cPages, pReq->aPhysPage);
- if (pReq->fInflate)
- STAM_REL_U32_INC(&pThis->StatMemBalloonChunks);
- else
- STAM_REL_U32_DEC(&pThis->StatMemBalloonChunks);
- return rc;
- }
- /**
- * Handles VMMDevReq_GetStatisticsChangeRequest.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetStatisticsChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevGetStatisticsChangeRequest *pReq = (VMMDevGetStatisticsChangeRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
- /* just pass on the information */
- Log(("VMMDev: returning statistics interval %d seconds\n", pThis->u32StatIntervalSize));
- pReq->u32StatInterval = pThis->u32StatIntervalSize;
- if (pReq->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
- {
- /* Remember which mode the client has queried. */
- pThis->u32LastStatIntervalSize= pThis->u32StatIntervalSize;
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_ReportGuestStats.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_ReportGuestStats(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReportGuestStats *pReq = (VMMDevReportGuestStats *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- Log(("VMMDevReq_ReportGuestStats\n"));
- #ifdef LOG_ENABLED
- VBoxGuestStatistics *pGuestStats = &pReq->guestStats;
- Log(("Current statistics:\n"));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
- Log(("CPU%u: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
- Log(("CPU%u: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
- Log(("CPU%u: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
- Log(("CPU%u: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
- Log(("CPU%u: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
- Log(("CPU%u: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
- Log(("CPU%u: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
- /* Note that reported values are in pages; upper layers expect them in megabytes */
- Log(("CPU%u: Page size %-4d bytes\n", pGuestStats->u32CpuId, pGuestStats->u32PageSize));
- Assert(pGuestStats->u32PageSize == 4096);
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
- Log(("CPU%u: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/_4K)-1) / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
- Log(("CPU%u: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
- Log(("CPU%u: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
- Log(("CPU%u: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
- Log(("CPU%u: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
- Log(("CPU%u: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
- Log(("CPU%u: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
- Log(("CPU%u: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/_4K)));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
- Log(("CPU%u: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/_4K)));
- Log(("Statistics end *******************\n"));
- #endif /* LOG_ENABLED */
- /* forward the call */
- return pThis->pDrv->pfnReportStatistics(pThis->pDrv, &pReq->guestStats);
- }
- /**
- * Handles VMMDevReq_QueryCredentials.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_QueryCredentials(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* let's start by nulling out the data */
- memset(pReq->szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pReq->szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pReq->szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- /* should we return whether we got credentials for a logon? */
- if (pReq->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
- {
- if ( pThis->pCredentials->Logon.szUserName[0]
- || pThis->pCredentials->Logon.szPassword[0]
- || pThis->pCredentials->Logon.szDomain[0])
- pReq->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
- else
- pReq->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
- }
- /* does the guest want to read logon credentials? */
- if (pReq->u32Flags & VMMDEV_CREDENTIALS_READ)
- {
- if (pThis->pCredentials->Logon.szUserName[0])
- strcpy(pReq->szUserName, pThis->pCredentials->Logon.szUserName);
- if (pThis->pCredentials->Logon.szPassword[0])
- strcpy(pReq->szPassword, pThis->pCredentials->Logon.szPassword);
- if (pThis->pCredentials->Logon.szDomain[0])
- strcpy(pReq->szDomain, pThis->pCredentials->Logon.szDomain);
- if (!pThis->pCredentials->Logon.fAllowInteractiveLogon)
- pReq->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
- else
- pReq->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
- }
- if (!pThis->fKeepCredentials)
- {
- /* does the caller want us to destroy the logon credentials? */
- if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
- {
- memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- }
- }
- /* does the guest want to read credentials for verification? */
- if (pReq->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
- {
- if (pThis->pCredentials->Judge.szUserName[0])
- strcpy(pReq->szUserName, pThis->pCredentials->Judge.szUserName);
- if (pThis->pCredentials->Judge.szPassword[0])
- strcpy(pReq->szPassword, pThis->pCredentials->Judge.szPassword);
- if (pThis->pCredentials->Judge.szDomain[0])
- strcpy(pReq->szDomain, pThis->pCredentials->Judge.szDomain);
- }
- /* does the caller want us to destroy the judgement credentials? */
- if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
- {
- memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_ReportCredentialsJudgement.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_ReportCredentialsJudgement(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /* what does the guest think about the credentials? (note: the order is important here!) */
- if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
- pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
- else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
- pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
- else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
- pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
- else
- {
- Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", pReq->u32Flags));
- /** @todo why don't we return VERR_INVALID_PARAMETER to the guest? */
- }
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetHostVersion.
- *
- * @returns VBox status code that the guest should see.
- * @param pReqHdr The header of the request to handle.
- * @since 3.1.0
- * @note The ring-0 VBoxGuestLib uses this to check whether
- * VMMDevHGCMParmType_PageList is supported.
- */
- static int vmmdevReqHandler_GetHostVersion(VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqHostVersion *pReq = (VMMDevReqHostVersion *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- pReq->major = RTBldCfgVersionMajor();
- pReq->minor = RTBldCfgVersionMinor();
- pReq->build = RTBldCfgVersionBuild();
- pReq->revision = RTBldCfgRevision();
- pReq->features = VMMDEV_HVF_HGCM_PHYS_PAGE_LIST;
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_GetCpuHotPlugRequest.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetCpuHotPlugRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevGetCpuHotPlugRequest *pReq = (VMMDevGetCpuHotPlugRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- pReq->enmEventType = pThis->enmCpuHotPlugEvent;
- pReq->idCpuCore = pThis->idCpuCore;
- pReq->idCpuPackage = pThis->idCpuPackage;
- /* Clear the event */
- pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_None;
- pThis->idCpuCore = UINT32_MAX;
- pThis->idCpuPackage = UINT32_MAX;
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_SetCpuHotPlugStatus.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_SetCpuHotPlugStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevCpuHotPlugStatusRequest *pReq = (VMMDevCpuHotPlugStatusRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- if (pReq->enmStatusType == VMMDevCpuStatusType_Disable)
- pThis->fCpuHotPlugEventsEnabled = false;
- else if (pReq->enmStatusType == VMMDevCpuStatusType_Enable)
- pThis->fCpuHotPlugEventsEnabled = true;
- else
- return VERR_INVALID_PARAMETER;
- return VINF_SUCCESS;
- }
- #ifdef DEBUG
- /**
- * Handles VMMDevReq_LogString.
- *
- * @returns VBox status code that the guest should see.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_LogString(VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqLogString *pReq = (VMMDevReqLogString *)pReqHdr;
- AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- AssertMsgReturn(pReq->szString[pReq->header.size - RT_OFFSETOF(VMMDevReqLogString, szString) - 1] == '\0',
- ("not null terminated\n"), VERR_INVALID_PARAMETER);
- LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("DEBUG LOG: %s", pReq->szString));
- return VINF_SUCCESS;
- }
- #endif /* DEBUG */
- /**
- * Handles VMMDevReq_GetSessionId.
- *
- * Get a unique "session" ID for this VM, where the ID will be different after each
- * start, reset or restore of the VM. This can be used for restore detection
- * inside the guest.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetSessionId(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqSessionId *pReq = (VMMDevReqSessionId *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- pReq->idSession = pThis->idSession;
- return VINF_SUCCESS;
- }
- #ifdef VBOX_WITH_PAGE_SHARING
- /**
- * Handles VMMDevReq_RegisterSharedModule.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_RegisterSharedModule(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- /*
- * Basic input validation (more done by GMM).
- */
- VMMDevSharedModuleRegistrationRequest *pReq = (VMMDevSharedModuleRegistrationRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size >= sizeof(VMMDevSharedModuleRegistrationRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- AssertMsgReturn(pReq->header.size == RT_UOFFSETOF(VMMDevSharedModuleRegistrationRequest, aRegions[pReq->cRegions]),
- ("%u cRegions=%u\n", pReq->header.size, pReq->cRegions), VERR_INVALID_PARAMETER);
- AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
- AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
- int rc = RTStrValidateEncoding(pReq->szName);
- AssertRCReturn(rc, rc);
- rc = RTStrValidateEncoding(pReq->szVersion);
- AssertRCReturn(rc, rc);
- /*
- * Forward the request to the VMM.
- */
- return PGMR3SharedModuleRegister(PDMDevHlpGetVM(pThis->pDevIns), pReq->enmGuestOS, pReq->szName, pReq->szVersion,
- pReq->GCBaseAddr, pReq->cbModule, pReq->cRegions, pReq->aRegions);
- }
- /**
- * Handles VMMDevReq_UnregisterSharedModule.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_UnregisterSharedModule(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- /*
- * Basic input validation.
- */
- VMMDevSharedModuleUnregistrationRequest *pReq = (VMMDevSharedModuleUnregistrationRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleUnregistrationRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
- AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
- int rc = RTStrValidateEncoding(pReq->szName);
- AssertRCReturn(rc, rc);
- rc = RTStrValidateEncoding(pReq->szVersion);
- AssertRCReturn(rc, rc);
- /*
- * Forward the request to the VMM.
- */
- return PGMR3SharedModuleUnregister(PDMDevHlpGetVM(pThis->pDevIns), pReq->szName, pReq->szVersion,
- pReq->GCBaseAddr, pReq->cbModule);
- }
- /**
- * Handles VMMDevReq_CheckSharedModules.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_CheckSharedModules(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevSharedModuleCheckRequest *pReq = (VMMDevSharedModuleCheckRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleCheckRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- return PGMR3SharedModuleCheckAll(PDMDevHlpGetVM(pThis->pDevIns));
- }
- /**
- * Handles VMMDevReq_GetPageSharingStatus.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_GetPageSharingStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevPageSharingStatusRequest *pReq = (VMMDevPageSharingStatusRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageSharingStatusRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- pReq->fEnabled = false;
- int rc = pThis->pDrv->pfnIsPageFusionEnabled(pThis->pDrv, &pReq->fEnabled);
- if (RT_FAILURE(rc))
- pReq->fEnabled = false;
- return VINF_SUCCESS;
- }
- /**
- * Handles VMMDevReq_DebugIsPageShared.
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr The header of the request to handle.
- */
- static int vmmdevReqHandler_DebugIsPageShared(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevPageIsSharedRequest *pReq = (VMMDevPageIsSharedRequest *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageIsSharedRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- # ifdef DEBUG
- return PGMR3SharedModuleGetPageState(PDMDevHlpGetVM(pThis->pDevIns), pReq->GCPtrPage, &pReq->fShared, &pReq->uPageFlags);
- # else
- RT_NOREF1(pThis);
- return VERR_NOT_IMPLEMENTED;
- # endif
- }
- #endif /* VBOX_WITH_PAGE_SHARING */
- /**
- * Handles VMMDevReq_WriteCoreDumpe
- *
- * @returns VBox status code that the guest should see.
- * @param pThis The VMMDev instance data.
- * @param pReqHdr Pointer to the request header.
- */
- static int vmmdevReqHandler_WriteCoreDump(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
- {
- VMMDevReqWriteCoreDump *pReq = (VMMDevReqWriteCoreDump *)pReqHdr;
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevReqWriteCoreDump), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- /*
- * Only available if explicitly enabled by the user.
- */
- if (!pThis->fGuestCoreDumpEnabled)
- return VERR_ACCESS_DENIED;
- /*
- * User makes sure the directory exists before composing the path.
- */
- if (!RTDirExists(pThis->szGuestCoreDumpDir))
- return VERR_PATH_NOT_FOUND;
- char szCorePath[RTPATH_MAX];
- RTStrCopy(szCorePath, sizeof(szCorePath), pThis->szGuestCoreDumpDir);
- RTPathAppend(szCorePath, sizeof(szCorePath), "VBox.core");
- /*
- * Rotate existing cores based on number of additional cores to keep around.
- */
- if (pThis->cGuestCoreDumps > 0)
- for (int64_t i = pThis->cGuestCoreDumps - 1; i >= 0; i--)
- {
- char szFilePathOld[RTPATH_MAX];
- if (i == 0)
- RTStrCopy(szFilePathOld, sizeof(szFilePathOld), szCorePath);
- else
- RTStrPrintf(szFilePathOld, sizeof(szFilePathOld), "%s.%lld", szCorePath, i);
- char szFilePathNew[RTPATH_MAX];
- RTStrPrintf(szFilePathNew, sizeof(szFilePathNew), "%s.%lld", szCorePath, i + 1);
- int vrc = RTFileMove(szFilePathOld, szFilePathNew, RTFILEMOVE_FLAGS_REPLACE);
- if (vrc == VERR_FILE_NOT_FOUND)
- RTFileDelete(szFilePathNew);
- }
- /*
- * Write the core file.
- */
- PUVM pUVM = PDMDevHlpGetUVM(pThis->pDevIns);
- return DBGFR3CoreWrite(pUVM, szCorePath, true /*fReplaceFile*/);
- }
- /**
- * Dispatch the request to the appropriate handler function.
- *
- * @returns Port I/O handler exit code.
- * @param pThis The VMM device instance data.
- * @param pReqHdr The request header (cached in host memory).
- * @param GCPhysReqHdr The guest physical address of the request (for
- * HGCM).
- * @param pfDelayedUnlock Where to indicate whether the critical section exit
- * needs to be delayed till after the request has been
- * written back. This is a HGCM kludge, see critsect
- * work in hgcmCompletedWorker for more details.
- */
- static int vmmdevReqDispatcher(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr, bool *pfDelayedUnlock)
- {
- int rcRet = VINF_SUCCESS;
- *pfDelayedUnlock = false;
- switch (pReqHdr->requestType)
- {
- case VMMDevReq_ReportGuestInfo:
- pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo(pThis, pReqHdr);
- break;
- case VMMDevReq_ReportGuestInfo2:
- pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo2(pThis, pReqHdr);
- break;
- case VMMDevReq_ReportGuestStatus:
- pReqHdr->rc = vmmdevReqHandler_ReportGuestStatus(pThis, pReqHdr);
- break;
- case VMMDevReq_ReportGuestUserState:
- pReqHdr->rc = vmmdevReqHandler_ReportGuestUserState(pThis, pReqHdr);
- break;
- case VMMDevReq_ReportGuestCapabilities:
- pReqHdr->rc = vmmdevReqHandler_ReportGuestCapabilities(pThis, pReqHdr);
- break;
- case VMMDevReq_SetGuestCapabilities:
- pReqHdr->rc = vmmdevReqHandler_SetGuestCapabilities(pThis, pReqHdr);
- break;
- case VMMDevReq_WriteCoreDump:
- pReqHdr->rc = vmmdevReqHandler_WriteCoreDump(pThis, pReqHdr);
- break;
- case VMMDevReq_GetMouseStatus:
- pReqHdr->rc = vmmdevReqHandler_GetMouseStatus(pThis, pReqHdr);
- break;
- case VMMDevReq_SetMouseStatus:
- pReqHdr->rc = vmmdevReqHandler_SetMouseStatus(pThis, pReqHdr);
- break;
- case VMMDevReq_SetPointerShape:
- pReqHdr->rc = vmmdevReqHandler_SetPointerShape(pThis, pReqHdr);
- break;
- case VMMDevReq_GetHostTime:
- pReqHdr->rc = vmmdevReqHandler_GetHostTime(pThis, pReqHdr);
- break;
- case VMMDevReq_GetHypervisorInfo:
- pReqHdr->rc = vmmdevReqHandler_GetHypervisorInfo(pThis, pReqHdr);
- break;
- case VMMDevReq_SetHypervisorInfo:
- pReqHdr->rc = vmmdevReqHandler_SetHypervisorInfo(pThis, pReqHdr);
- break;
- case VMMDevReq_RegisterPatchMemory:
- pReqHdr->rc = vmmdevReqHandler_RegisterPatchMemory(pThis, pReqHdr);
- break;
- case VMMDevReq_DeregisterPatchMemory:
- pReqHdr->rc = vmmdevReqHandler_DeregisterPatchMemory(pThis, pReqHdr);
- break;
- case VMMDevReq_SetPowerStatus:
- {
- int rc = pReqHdr->rc = vmmdevReqHandler_SetPowerStatus(pThis, pReqHdr);
- if (rc != VINF_SUCCESS && RT_SUCCESS(rc))
- rcRet = rc;
- break;
- }
- case VMMDevReq_GetDisplayChangeRequest:
- pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest(pThis, pReqHdr);
- break;
- case VMMDevReq_GetDisplayChangeRequest2:
- pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest2(pThis, pReqHdr);
- break;
- case VMMDevReq_GetDisplayChangeRequestEx:
- pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequestEx(pThis, pReqHdr);
- break;
- case VMMDevReq_VideoModeSupported:
- pReqHdr->rc = vmmdevReqHandler_VideoModeSupported(pThis, pReqHdr);
- break;
- case VMMDevReq_VideoModeSupported2:
- pReqHdr->rc = vmmdevReqHandler_VideoModeSupported2(pThis, pReqHdr);
- break;
- case VMMDevReq_GetHeightReduction:
- pReqHdr->rc = vmmdevReqHandler_GetHeightReduction(pThis, pReqHdr);
- break;
- case VMMDevReq_AcknowledgeEvents:
- pReqHdr->rc = vmmdevReqHandler_AcknowledgeEvents(pThis, pReqHdr);
- break;
- case VMMDevReq_CtlGuestFilterMask:
- pReqHdr->rc = vmmdevReqHandler_CtlGuestFilterMask(pThis, pReqHdr);
- break;
- #ifdef VBOX_WITH_HGCM
- case VMMDevReq_HGCMConnect:
- pReqHdr->rc = vmmdevReqHandler_HGCMConnect(pThis, pReqHdr, GCPhysReqHdr);
- *pfDelayedUnlock = true;
- break;
- case VMMDevReq_HGCMDisconnect:
- pReqHdr->rc = vmmdevReqHandler_HGCMDisconnect(pThis, pReqHdr, GCPhysReqHdr);
- *pfDelayedUnlock = true;
- break;
- # ifdef VBOX_WITH_64_BITS_GUESTS
- case VMMDevReq_HGCMCall32:
- case VMMDevReq_HGCMCall64:
- # else
- case VMMDevReq_HGCMCall:
- # endif /* VBOX_WITH_64_BITS_GUESTS */
- pReqHdr->rc = vmmdevReqHandler_HGCMCall(pThis, pReqHdr, GCPhysReqHdr);
- *pfDelayedUnlock = true;
- break;
- case VMMDevReq_HGCMCancel:
- pReqHdr->rc = vmmdevReqHandler_HGCMCancel(pThis, pReqHdr, GCPhysReqHdr);
- *pfDelayedUnlock = true;
- break;
- case VMMDevReq_HGCMCancel2:
- pReqHdr->rc = vmmdevReqHandler_HGCMCancel2(pThis, pReqHdr);
- break;
- #endif /* VBOX_WITH_HGCM */
- case VMMDevReq_VideoAccelEnable:
- pReqHdr->rc = vmmdevReqHandler_VideoAccelEnable(pThis, pReqHdr);
- break;
- case VMMDevReq_VideoAccelFlush:
- pReqHdr->rc = vmmdevReqHandler_VideoAccelFlush(pThis, pReqHdr);
- break;
- case VMMDevReq_VideoSetVisibleRegion:
- pReqHdr->rc = vmmdevReqHandler_VideoSetVisibleRegion(pThis, pReqHdr);
- break;
- case VMMDevReq_GetSeamlessChangeRequest:
- pReqHdr->rc = vmmdevReqHandler_GetSeamlessChangeRequest(pThis, pReqHdr);
- break;
- case VMMDevReq_GetVRDPChangeRequest:
- pReqHdr->rc = vmmdevReqHandler_GetVRDPChangeRequest(pThis, pReqHdr);
- break;
- case VMMDevReq_GetMemBalloonChangeRequest:
- pReqHdr->rc = vmmdevReqHandler_GetMemBalloonChangeRequest(pThis, pReqHdr);
- break;
- case VMMDevReq_ChangeMemBalloon:
- pReqHdr->rc = vmmdevReqHandler_ChangeMemBalloon(pThis, pReqHdr);
- break;
- case VMMDevReq_GetStatisticsChangeRequest:
- pReqHdr->rc = vmmdevReqHandler_GetStatisticsChangeRequest(pThis, pReqHdr);
- break;
- case VMMDevReq_ReportGuestStats:
- pReqHdr->rc = vmmdevReqHandler_ReportGuestStats(pThis, pReqHdr);
- break;
- case VMMDevReq_QueryCredentials:
- pReqHdr->rc = vmmdevReqHandler_QueryCredentials(pThis, pReqHdr);
- break;
- case VMMDevReq_ReportCredentialsJudgement:
- pReqHdr->rc = vmmdevReqHandler_ReportCredentialsJudgement(pThis, pReqHdr);
- break;
- case VMMDevReq_GetHostVersion:
- pReqHdr->rc = vmmdevReqHandler_GetHostVersion(pReqHdr);
- break;
- case VMMDevReq_GetCpuHotPlugRequest:
- pReqHdr->rc = vmmdevReqHandler_GetCpuHotPlugRequest(pThis, pReqHdr);
- break;
- case VMMDevReq_SetCpuHotPlugStatus:
- pReqHdr->rc = vmmdevReqHandler_SetCpuHotPlugStatus(pThis, pReqHdr);
- break;
- #ifdef VBOX_WITH_PAGE_SHARING
- case VMMDevReq_RegisterSharedModule:
- pReqHdr->rc = vmmdevReqHandler_RegisterSharedModule(pThis, pReqHdr);
- break;
- case VMMDevReq_UnregisterSharedModule:
- pReqHdr->rc = vmmdevReqHandler_UnregisterSharedModule(pThis, pReqHdr);
- break;
- case VMMDevReq_CheckSharedModules:
- pReqHdr->rc = vmmdevReqHandler_CheckSharedModules(pThis, pReqHdr);
- break;
- case VMMDevReq_GetPageSharingStatus:
- pReqHdr->rc = vmmdevReqHandler_GetPageSharingStatus(pThis, pReqHdr);
- break;
- case VMMDevReq_DebugIsPageShared:
- pReqHdr->rc = vmmdevReqHandler_DebugIsPageShared(pThis, pReqHdr);
- break;
- #endif /* VBOX_WITH_PAGE_SHARING */
- #ifdef DEBUG
- case VMMDevReq_LogString:
- pReqHdr->rc = vmmdevReqHandler_LogString(pReqHdr);
- break;
- #endif
- case VMMDevReq_GetSessionId:
- pReqHdr->rc = vmmdevReqHandler_GetSessionId(pThis, pReqHdr);
- break;
- /*
- * Guest wants to give up a timeslice.
- * Note! This was only ever used by experimental GAs!
- */
- /** @todo maybe we could just remove this? */
- case VMMDevReq_Idle:
- {
- /* just return to EMT telling it that we want to halt */
- rcRet = VINF_EM_HALT;
- break;
- }
- case VMMDevReq_GuestHeartbeat:
- pReqHdr->rc = vmmDevReqHandler_GuestHeartbeat(pThis);
- break;
- case VMMDevReq_HeartbeatConfigure:
- pReqHdr->rc = vmmDevReqHandler_HeartbeatConfigure(pThis, pReqHdr);
- break;
- default:
- {
- pReqHdr->rc = VERR_NOT_IMPLEMENTED;
- Log(("VMMDev unknown request type %d\n", pReqHdr->requestType));
- break;
- }
- }
- return rcRet;
- }
- /**
- * @callback_method_impl{FNIOMIOPORTOUT, Port I/O Handler for the generic
- * request interface.}
- */
- static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
- {
- RT_NOREF2(Port, cb);
- PVMMDEV pThis = (VMMDevState*)pvUser;
- /*
- * The caller has passed the guest context physical address of the request
- * structure. We'll copy all of it into a heap buffer eventually, but we
- * will have to start off with the header.
- */
- VMMDevRequestHeader requestHeader;
- RT_ZERO(requestHeader);
- PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
- /* The structure size must be greater or equal to the header size. */
- if (requestHeader.size < sizeof(VMMDevRequestHeader))
- {
- Log(("VMMDev request header size too small! size = %d\n", requestHeader.size));
- return VINF_SUCCESS;
- }
- /* Check the version of the header structure. */
- if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
- {
- Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
- return VINF_SUCCESS;
- }
- Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
- int rcRet = VINF_SUCCESS;
- bool fDelayedUnlock = false;
- VMMDevRequestHeader *pRequestHeader = NULL;
- /* Check that is doesn't exceed the max packet size. */
- if (requestHeader.size <= VMMDEV_MAX_VMMDEVREQ_SIZE)
- {
- /*
- * We require the GAs to report it's information before we let it have
- * access to all the functions. The VMMDevReq_ReportGuestInfo request
- * is the one which unlocks the access. Newer additions will first
- * issue VMMDevReq_ReportGuestInfo2, older ones doesn't know this one.
- * Two exceptions: VMMDevReq_GetHostVersion and VMMDevReq_WriteCoreDump.
- */
- if ( pThis->fu32AdditionsOk
- || requestHeader.requestType == VMMDevReq_ReportGuestInfo2
- || requestHeader.requestType == VMMDevReq_ReportGuestInfo
- || requestHeader.requestType == VMMDevReq_WriteCoreDump
- || requestHeader.requestType == VMMDevReq_GetHostVersion
- )
- {
- /*
- * The request looks fine. Allocate a heap block for it, read the
- * entire package from guest memory and feed it to the dispatcher.
- */
- pRequestHeader = (VMMDevRequestHeader *)RTMemAlloc(requestHeader.size);
- if (pRequestHeader)
- {
- memcpy(pRequestHeader, &requestHeader, sizeof(VMMDevRequestHeader));
- size_t cbLeft = requestHeader.size - sizeof(VMMDevRequestHeader);
- if (cbLeft)
- PDMDevHlpPhysRead(pDevIns,
- (RTGCPHYS)u32 + sizeof(VMMDevRequestHeader),
- (uint8_t *)pRequestHeader + sizeof(VMMDevRequestHeader),
- cbLeft);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- rcRet = vmmdevReqDispatcher(pThis, pRequestHeader, u32, &fDelayedUnlock);
- if (!fDelayedUnlock)
- PDMCritSectLeave(&pThis->CritSect);
- }
- else
- {
- Log(("VMMDev: RTMemAlloc failed!\n"));
- requestHeader.rc = VERR_NO_MEMORY;
- }
- }
- else
- {
- LogRelMax(10, ("VMMDev: Guest has not yet reported to us -- refusing operation of request #%d\n",
- requestHeader.requestType));
- requestHeader.rc = VERR_NOT_SUPPORTED;
- }
- }
- else
- {
- LogRelMax(50, ("VMMDev: Request packet too big (%x), refusing operation\n", requestHeader.size));
- requestHeader.rc = VERR_NOT_SUPPORTED;
- }
- /*
- * Write the result back to guest memory
- */
- if (pRequestHeader)
- {
- PDMDevHlpPhysWrite(pDevIns, u32, pRequestHeader, pRequestHeader->size);
- if (fDelayedUnlock)
- PDMCritSectLeave(&pThis->CritSect);
- RTMemFree(pRequestHeader);
- }
- else
- {
- /* early error case; write back header only */
- PDMDevHlpPhysWrite(pDevIns, u32, &requestHeader, sizeof(requestHeader));
- Assert(!fDelayedUnlock);
- }
- return rcRet;
- }
- /* -=-=-=-=-=- PCI Device -=-=-=-=-=- */
- /**
- * @callback_method_impl{FNPCIIOREGIONMAP,MMIO/MMIO2 regions}
- */
- static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
- RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
- {
- RT_NOREF1(cb);
- LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
- PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
- int rc;
- if (iRegion == 1)
- {
- AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM, VERR_INTERNAL_ERROR);
- Assert(pThis->pVMMDevRAMR3 != NULL);
- if (GCPhysAddress != NIL_RTGCPHYS)
- {
- /*
- * Map the MMIO2 memory.
- */
- pThis->GCPhysVMMDevRAM = GCPhysAddress;
- Assert(pThis->GCPhysVMMDevRAM == GCPhysAddress);
- rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
- }
- else
- {
- /*
- * It is about to be unmapped, just clean up.
- */
- pThis->GCPhysVMMDevRAM = NIL_RTGCPHYS32;
- rc = VINF_SUCCESS;
- }
- }
- else if (iRegion == 2)
- {
- AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
- Assert(pThis->pVMMDevHeapR3 != NULL);
- if (GCPhysAddress != NIL_RTGCPHYS)
- {
- /*
- * Map the MMIO2 memory.
- */
- pThis->GCPhysVMMDevHeap = GCPhysAddress;
- Assert(pThis->GCPhysVMMDevHeap == GCPhysAddress);
- rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
- if (RT_SUCCESS(rc))
- rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, GCPhysAddress, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
- }
- else
- {
- /*
- * It is about to be unmapped, just clean up.
- */
- PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
- pThis->GCPhysVMMDevHeap = NIL_RTGCPHYS32;
- rc = VINF_SUCCESS;
- }
- }
- else
- {
- AssertMsgFailed(("%d\n", iRegion));
- rc = VERR_INVALID_PARAMETER;
- }
- return rc;
- }
- /**
- * @callback_method_impl{FNPCIIOREGIONMAP,I/O Port Region}
- */
- static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
- RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
- {
- RT_NOREF3(iRegion, cb, enmType);
- PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
- Assert(enmType == PCI_ADDRESS_SPACE_IO);
- Assert(iRegion == 0);
- AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
- /*
- * Register our port IO handlers.
- */
- int rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
- pThis, vmmdevRequestHandler, NULL, NULL, NULL, "VMMDev Request Handler");
- AssertRC(rc);
- return rc;
- }
- /* -=-=-=-=-=- Backdoor Logging and Time Sync. -=-=-=-=-=- */
- /**
- * @callback_method_impl{FNIOMIOPORTOUT, Backdoor Logging.}
- */
- static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
- {
- RT_NOREF1(pvUser);
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
- if (!pThis->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
- {
- /* The raw version. */
- switch (u32)
- {
- case '\r': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
- case '\n': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
- case '\t': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
- default: LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: %c (%02x)\n", u32, u32)); break;
- }
- /* The readable, buffered version. */
- if (u32 == '\n' || u32 == '\r')
- {
- pThis->szMsg[pThis->iMsg] = '\0';
- if (pThis->iMsg)
- LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %s\n", pThis->szMsg));
- pThis->iMsg = 0;
- }
- else
- {
- if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
- {
- pThis->szMsg[pThis->iMsg] = '\0';
- LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %s\n", pThis->szMsg));
- pThis->iMsg = 0;
- }
- pThis->szMsg[pThis->iMsg] = (char )u32;
- pThis->szMsg[++pThis->iMsg] = '\0';
- }
- }
- return VINF_SUCCESS;
- }
- #ifdef VMMDEV_WITH_ALT_TIMESYNC
- /**
- * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
- */
- static DECLCALLBACK(int) vmmdevAltTimeSyncWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
- {
- RT_NOREF2(pvUser, Port);
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
- if (cb == 4)
- {
- /* Selects high (0) or low (1) DWORD. The high has to be read first. */
- switch (u32)
- {
- case 0:
- pThis->fTimesyncBackdoorLo = false;
- break;
- case 1:
- pThis->fTimesyncBackdoorLo = true;
- break;
- default:
- Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
- break;
- }
- }
- else
- Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
- return VINF_SUCCESS;
- }
- /**
- * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
- */
- static DECLCALLBACK(int) vmmdevAltTimeSyncRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
- {
- RT_NOREF2(pvUser, Port);
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
- int rc;
- if (cb == 4)
- {
- if (pThis->fTimesyncBackdoorLo)
- *pu32 = (uint32_t)pThis->hostTime;
- else
- {
- /* Reading the high dword gets and saves the current time. */
- RTTIMESPEC Now;
- pThis->hostTime = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &Now));
- *pu32 = (uint32_t)(pThis->hostTime >> 32);
- }
- rc = VINF_SUCCESS;
- }
- else
- {
- Log(("vmmdevAltTimeSyncRead: Invalid access cb=%#x\n", cb));
- rc = VERR_IOM_IOPORT_UNUSED;
- }
- return rc;
- }
- #endif /* VMMDEV_WITH_ALT_TIMESYNC */
- /* -=-=-=-=-=- IBase -=-=-=-=-=- */
- /**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
- static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThis->IPort);
- #ifdef VBOX_WITH_HGCM
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMPORT, &pThis->IHGCMPort);
- #endif
- /* Currently only for shared folders. */
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->SharedFolders.ILeds);
- return NULL;
- }
- /* -=-=-=-=-=- ILeds -=-=-=-=-=- */
- /**
- * Gets the pointer to the status LED of a unit.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param iLUN The unit which status LED we desire.
- * @param ppLed Where to store the LED pointer.
- */
- static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, SharedFolders.ILeds);
- if (iLUN == 0) /* LUN 0 is shared folders */
- {
- *ppLed = &pThis->SharedFolders.Led;
- return VINF_SUCCESS;
- }
- return VERR_PDM_LUN_NOT_FOUND;
- }
- /* -=-=-=-=-=- PDMIVMMDEVPORT (VMMDEV::IPort) -=-=-=-=-=- */
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryAbsoluteMouse}
- */
- static DECLCALLBACK(int) vmmdevIPort_QueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- /** @todo at the first sign of trouble in this area, just enter the critsect.
- * As indicated by the comment below, the atomic reads serves no real purpose
- * here since we can assume cache coherency protocoles and int32_t alignment
- * rules making sure we won't see a halfwritten value. */
- if (pxAbs)
- *pxAbs = ASMAtomicReadS32(&pThis->mouseXAbs); /* why the atomic read? */
- if (pyAbs)
- *pyAbs = ASMAtomicReadS32(&pThis->mouseYAbs);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnSetAbsoluteMouse}
- */
- static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- if ( pThis->mouseXAbs != xAbs
- || pThis->mouseYAbs != yAbs)
- {
- Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d\n", xAbs, yAbs));
- pThis->mouseXAbs = xAbs;
- pThis->mouseYAbs = yAbs;
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryMouseCapabilities}
- */
- static DECLCALLBACK(int) vmmdevIPort_QueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- AssertPtrReturn(pfCapabilities, VERR_INVALID_PARAMETER);
- *pfCapabilities = pThis->mouseCapabilities;
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnUpdateMouseCapabilities}
- */
- static DECLCALLBACK(int)
- vmmdevIPort_UpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- uint32_t fOldCaps = pThis->mouseCapabilities;
- pThis->mouseCapabilities &= ~(fCapsRemoved & VMMDEV_MOUSE_HOST_MASK);
- pThis->mouseCapabilities |= (fCapsAdded & VMMDEV_MOUSE_HOST_MASK)
- | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
- bool fNotify = fOldCaps != pThis->mouseCapabilities;
- LogRelFlow(("VMMDev: vmmdevIPort_UpdateMouseCapabilities: fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify=%RTbool\n", fCapsAdded,
- fCapsRemoved, fNotify));
- if (fNotify)
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestDisplayChange}
- */
- static DECLCALLBACK(int)
- vmmdevIPort_RequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t cx, uint32_t cy, uint32_t cBits, uint32_t idxDisplay,
- int32_t xOrigin, int32_t yOrigin, bool fEnabled, bool fChangeOrigin)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- if (idxDisplay >= RT_ELEMENTS(pThis->displayChangeData.aRequests))
- return VERR_INVALID_PARAMETER;
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[idxDisplay];
- /* Verify that the new resolution is different and that guest does not yet know about it. */
- bool fSameResolution = (!cx || pRequest->lastReadDisplayChangeRequest.xres == cx)
- && (!cy || pRequest->lastReadDisplayChangeRequest.yres == cy)
- && (!cBits || pRequest->lastReadDisplayChangeRequest.bpp == cBits)
- && pRequest->lastReadDisplayChangeRequest.xOrigin == xOrigin
- && pRequest->lastReadDisplayChangeRequest.yOrigin == yOrigin
- && pRequest->lastReadDisplayChangeRequest.fEnabled == fEnabled
- && pRequest->lastReadDisplayChangeRequest.display == idxDisplay;
- if (!cx && !cy && !cBits)
- {
- /* Special case of reset video mode. */
- fSameResolution = false;
- }
- Log3(("vmmdevIPort_RequestDisplayChange: same=%d. new: cx=%d, cy=%d, cBits=%d, idxDisplay=%d.\
- old: cx=%d, cy=%d, cBits=%d, idxDisplay=%d. \n \
- ,OriginX = %d , OriginY=%d, Enabled=%d, ChangeOrigin=%d\n",
- fSameResolution, cx, cy, cBits, idxDisplay, pRequest->lastReadDisplayChangeRequest.xres,
- pRequest->lastReadDisplayChangeRequest.yres, pRequest->lastReadDisplayChangeRequest.bpp,
- pRequest->lastReadDisplayChangeRequest.display,
- xOrigin, yOrigin, fEnabled, fChangeOrigin));
- /* we could validate the information here but hey, the guest can do that as well! */
- pRequest->displayChangeRequest.xres = cx;
- pRequest->displayChangeRequest.yres = cy;
- pRequest->displayChangeRequest.bpp = cBits;
- pRequest->displayChangeRequest.display = idxDisplay;
- pRequest->displayChangeRequest.xOrigin = xOrigin;
- pRequest->displayChangeRequest.yOrigin = yOrigin;
- pRequest->displayChangeRequest.fEnabled = fEnabled;
- pRequest->displayChangeRequest.fChangeOrigin = fChangeOrigin;
- pRequest->fPending = !fSameResolution;
- if (!fSameResolution)
- {
- LogRel(("VMMDev: SetVideoModeHint: Got a video mode hint (%dx%dx%d)@(%dx%d),(%d;%d) at %d\n",
- cx, cy, cBits, xOrigin, yOrigin, fEnabled, fChangeOrigin, idxDisplay));
- /* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestSeamlessChange}
- */
- static DECLCALLBACK(int) vmmdevIPort_RequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- /* Verify that the new resolution is different and that guest does not yet know about it. */
- bool fSameMode = (pThis->fLastSeamlessEnabled == fEnabled);
- Log(("vmmdevIPort_RequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
- if (!fSameMode)
- {
- /* we could validate the information here but hey, the guest can do that as well! */
- pThis->fSeamlessEnabled = fEnabled;
- /* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnSetMemoryBalloon}
- */
- static DECLCALLBACK(int) vmmdevIPort_SetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- /* Verify that the new resolution is different and that guest does not yet know about it. */
- Log(("vmmdevIPort_SetMemoryBalloon: old=%u new=%u\n", pThis->cMbMemoryBalloonLast, cMbBalloon));
- if (pThis->cMbMemoryBalloonLast != cMbBalloon)
- {
- /* we could validate the information here but hey, the guest can do that as well! */
- pThis->cMbMemoryBalloon = cMbBalloon;
- /* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnVRDPChange}
- */
- static DECLCALLBACK(int) vmmdevIPort_VRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
- Log(("vmmdevIPort_VRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
- if (!fSame)
- {
- pThis->fVRDPEnabled = fVRDPEnabled;
- pThis->uVRDPExperienceLevel = uVRDPExperienceLevel;
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_VRDP);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnSetStatisticsInterval}
- */
- static DECLCALLBACK(int) vmmdevIPort_SetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- /* Verify that the new resolution is different and that guest does not yet know about it. */
- bool fSame = (pThis->u32LastStatIntervalSize == cSecsStatInterval);
- Log(("vmmdevIPort_SetStatisticsInterval: old=%d. new=%d\n", pThis->u32LastStatIntervalSize, cSecsStatInterval));
- if (!fSame)
- {
- /* we could validate the information here but hey, the guest can do that as well! */
- pThis->u32StatIntervalSize = cSecsStatInterval;
- /* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnSetCredentials}
- */
- static DECLCALLBACK(int) vmmdevIPort_SetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
- const char *pszPassword, const char *pszDomain, uint32_t fFlags)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- AssertReturn(fFlags & (VMMDEV_SETCREDENTIALS_GUESTLOGON | VMMDEV_SETCREDENTIALS_JUDGE), VERR_INVALID_PARAMETER);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- /*
- * Logon mode
- */
- if (fFlags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
- {
- /* memorize the data */
- strcpy(pThis->pCredentials->Logon.szUserName, pszUsername);
- strcpy(pThis->pCredentials->Logon.szPassword, pszPassword);
- strcpy(pThis->pCredentials->Logon.szDomain, pszDomain);
- pThis->pCredentials->Logon.fAllowInteractiveLogon = !(fFlags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
- }
- /*
- * Credentials verification mode?
- */
- else
- {
- /* memorize the data */
- strcpy(pThis->pCredentials->Judge.szUserName, pszUsername);
- strcpy(pThis->pCredentials->Judge.szPassword, pszPassword);
- strcpy(pThis->pCredentials->Judge.szDomain, pszDomain);
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_JUDGE_CREDENTIALS);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnVBVAChange}
- *
- * Notification from the Display. Especially useful when acceleration is
- * disabled after a video mode change.
- */
- static DECLCALLBACK(void) vmmdevIPort_VBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- Log(("vmmdevIPort_VBVAChange: fEnabled = %d\n", fEnabled));
- /* Only used by saved state, which I guess is why we don't bother with locking here. */
- pThis->u32VideoAccelEnabled = fEnabled;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotUnplug}
- */
- static DECLCALLBACK(int) vmmdevIPort_CpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- int rc = VINF_SUCCESS;
- Log(("vmmdevIPort_CpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- if (pThis->fCpuHotPlugEventsEnabled)
- {
- pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
- pThis->idCpuCore = idCpuCore;
- pThis->idCpuPackage = idCpuPackage;
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
- }
- else
- rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
- PDMCritSectLeave(&pThis->CritSect);
- return rc;
- }
- /**
- * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotPlug}
- */
- static DECLCALLBACK(int) vmmdevIPort_CpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
- {
- PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- int rc = VINF_SUCCESS;
- Log(("vmmdevCpuPlug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- if (pThis->fCpuHotPlugEventsEnabled)
- {
- pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Plug;
- pThis->idCpuCore = idCpuCore;
- pThis->idCpuPackage = idCpuPackage;
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
- }
- else
- rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
- PDMCritSectLeave(&pThis->CritSect);
- return rc;
- }
- /* -=-=-=-=-=- Saved State -=-=-=-=-=- */
- /**
- * @callback_method_impl{FNSSMDEVLIVEEXEC}
- */
- static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
- {
- RT_NOREF1(uPass);
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
- SSMR3PutBool(pSSM, pThis->fGetHostTimeDisabled);
- SSMR3PutBool(pSSM, pThis->fBackdoorLogDisabled);
- SSMR3PutBool(pSSM, pThis->fKeepCredentials);
- SSMR3PutBool(pSSM, pThis->fHeapEnabled);
- return VINF_SSM_DONT_CALL_AGAIN;
- }
- /**
- * @callback_method_impl{FNSSMDEVSAVEEXEC}
- */
- static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
- {
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
- SSMR3PutU32(pSSM, pThis->hypervisorSize);
- SSMR3PutU32(pSSM, pThis->mouseCapabilities);
- SSMR3PutS32(pSSM, pThis->mouseXAbs);
- SSMR3PutS32(pSSM, pThis->mouseYAbs);
- SSMR3PutBool(pSSM, pThis->fNewGuestFilterMask);
- SSMR3PutU32(pSSM, pThis->u32NewGuestFilterMask);
- SSMR3PutU32(pSSM, pThis->u32GuestFilterMask);
- SSMR3PutU32(pSSM, pThis->u32HostEventFlags);
- /* The following is not strictly necessary as PGM restores MMIO2, keeping it for historical reasons. */
- SSMR3PutMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof(pThis->pVMMDevRAMR3->V));
- SSMR3PutMem(pSSM, &pThis->guestInfo, sizeof(pThis->guestInfo));
- SSMR3PutU32(pSSM, pThis->fu32AdditionsOk);
- SSMR3PutU32(pSSM, pThis->u32VideoAccelEnabled);
- SSMR3PutBool(pSSM, pThis->displayChangeData.fGuestSentChangeEventAck);
- SSMR3PutU32(pSSM, pThis->guestCaps);
- #ifdef VBOX_WITH_HGCM
- vmmdevHGCMSaveState(pThis, pSSM);
- #endif /* VBOX_WITH_HGCM */
- SSMR3PutU32(pSSM, pThis->fHostCursorRequested);
- SSMR3PutU32(pSSM, pThis->guestInfo2.uFullVersion);
- SSMR3PutU32(pSSM, pThis->guestInfo2.uRevision);
- SSMR3PutU32(pSSM, pThis->guestInfo2.fFeatures);
- SSMR3PutStrZ(pSSM, pThis->guestInfo2.szName);
- SSMR3PutU32(pSSM, pThis->cFacilityStatuses);
- for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++)
- {
- SSMR3PutU32(pSSM, pThis->aFacilityStatuses[i].enmFacility);
- SSMR3PutU32(pSSM, pThis->aFacilityStatuses[i].fFlags);
- SSMR3PutU16(pSSM, (uint16_t)pThis->aFacilityStatuses[i].enmStatus);
- SSMR3PutS64(pSSM, RTTimeSpecGetNano(&pThis->aFacilityStatuses[i].TimeSpecTS));
- }
- /* Heartbeat: */
- SSMR3PutBool(pSSM, pThis->fHeartbeatActive);
- SSMR3PutBool(pSSM, pThis->fFlatlined);
- SSMR3PutU64(pSSM, pThis->nsLastHeartbeatTS);
- TMR3TimerSave(pThis->pFlatlinedTimer, pSSM);
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
- }
- /**
- * @callback_method_impl{FNSSMDEVLOADEXEC}
- */
- static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
- {
- /** @todo The code load code is assuming we're always loaded into a freshly
- * constructed VM. */
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
- int rc;
- if ( uVersion > VMMDEV_SAVED_STATE_VERSION
- || uVersion < 6)
- return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
- /* config */
- if (uVersion > VMMDEV_SAVED_STATE_VERSION_VBOX_30)
- {
- bool f;
- rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
- if (pThis->fGetHostTimeDisabled != f)
- LogRel(("VMMDev: Config mismatch - fGetHostTimeDisabled: config=%RTbool saved=%RTbool\n", pThis->fGetHostTimeDisabled, f));
- rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
- if (pThis->fBackdoorLogDisabled != f)
- LogRel(("VMMDev: Config mismatch - fBackdoorLogDisabled: config=%RTbool saved=%RTbool\n", pThis->fBackdoorLogDisabled, f));
- rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
- if (pThis->fKeepCredentials != f)
- return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fKeepCredentials: config=%RTbool saved=%RTbool"),
- pThis->fKeepCredentials, f);
- rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
- if (pThis->fHeapEnabled != f)
- return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fHeapEnabled: config=%RTbool saved=%RTbool"),
- pThis->fHeapEnabled, f);
- }
- if (uPass != SSM_PASS_FINAL)
- return VINF_SUCCESS;
- /* state */
- SSMR3GetU32(pSSM, &pThis->hypervisorSize);
- SSMR3GetU32(pSSM, &pThis->mouseCapabilities);
- SSMR3GetS32(pSSM, &pThis->mouseXAbs);
- SSMR3GetS32(pSSM, &pThis->mouseYAbs);
- SSMR3GetBool(pSSM, &pThis->fNewGuestFilterMask);
- SSMR3GetU32(pSSM, &pThis->u32NewGuestFilterMask);
- SSMR3GetU32(pSSM, &pThis->u32GuestFilterMask);
- SSMR3GetU32(pSSM, &pThis->u32HostEventFlags);
- //SSMR3GetBool(pSSM, &pThis->pVMMDevRAMR3->fHaveEvents);
- // here be dragons (probably)
- SSMR3GetMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof (pThis->pVMMDevRAMR3->V));
- SSMR3GetMem(pSSM, &pThis->guestInfo, sizeof (pThis->guestInfo));
- SSMR3GetU32(pSSM, &pThis->fu32AdditionsOk);
- SSMR3GetU32(pSSM, &pThis->u32VideoAccelEnabled);
- if (uVersion > 10)
- SSMR3GetBool(pSSM, &pThis->displayChangeData.fGuestSentChangeEventAck);
- rc = SSMR3GetU32(pSSM, &pThis->guestCaps);
- /* Attributes which were temporarily introduced in r30072 */
- if (uVersion == 7)
- {
- uint32_t temp;
- SSMR3GetU32(pSSM, &temp);
- rc = SSMR3GetU32(pSSM, &temp);
- }
- AssertRCReturn(rc, rc);
- #ifdef VBOX_WITH_HGCM
- rc = vmmdevHGCMLoadState(pThis, pSSM, uVersion);
- AssertRCReturn(rc, rc);
- #endif /* VBOX_WITH_HGCM */
- if (uVersion >= 10)
- rc = SSMR3GetU32(pSSM, &pThis->fHostCursorRequested);
- AssertRCReturn(rc, rc);
- if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2)
- {
- SSMR3GetU32(pSSM, &pThis->guestInfo2.uFullVersion);
- SSMR3GetU32(pSSM, &pThis->guestInfo2.uRevision);
- SSMR3GetU32(pSSM, &pThis->guestInfo2.fFeatures);
- rc = SSMR3GetStrZ(pSSM, &pThis->guestInfo2.szName[0], sizeof(pThis->guestInfo2.szName));
- AssertRCReturn(rc, rc);
- }
- if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES)
- {
- uint32_t cFacilityStatuses;
- rc = SSMR3GetU32(pSSM, &cFacilityStatuses);
- AssertRCReturn(rc, rc);
- for (uint32_t i = 0; i < cFacilityStatuses; i++)
- {
- uint32_t uFacility, fFlags;
- uint16_t uStatus;
- int64_t iTimeStampNano;
- SSMR3GetU32(pSSM, &uFacility);
- SSMR3GetU32(pSSM, &fFlags);
- SSMR3GetU16(pSSM, &uStatus);
- rc = SSMR3GetS64(pSSM, &iTimeStampNano);
- AssertRCReturn(rc, rc);
- PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, (VBoxGuestFacilityType)uFacility);
- AssertLogRelMsgReturn(pEntry,
- ("VMMDev: Ran out of entries restoring the guest facility statuses. Saved state has %u.\n", cFacilityStatuses),
- VERR_OUT_OF_RESOURCES);
- pEntry->enmStatus = (VBoxGuestFacilityStatus)uStatus;
- pEntry->fFlags = fFlags;
- RTTimeSpecSetNano(&pEntry->TimeSpecTS, iTimeStampNano);
- }
- }
- /*
- * Heartbeat.
- */
- if (uVersion >= VMMDEV_SAVED_STATE_VERSION_HEARTBEAT)
- {
- SSMR3GetBool(pSSM, (bool *)&pThis->fHeartbeatActive);
- SSMR3GetBool(pSSM, (bool *)&pThis->fFlatlined);
- SSMR3GetU64(pSSM, (uint64_t *)&pThis->nsLastHeartbeatTS);
- rc = TMR3TimerLoad(pThis->pFlatlinedTimer, pSSM);
- AssertRCReturn(rc, rc);
- if (pThis->fFlatlined)
- LogRel(("vmmdevLoadState: Guest has flatlined. Last heartbeat %'RU64 ns before state was saved.\n",
- TMTimerGetNano(pThis->pFlatlinedTimer) - pThis->nsLastHeartbeatTS));
- }
- /*
- * On a resume, we send the capabilities changed message so
- * that listeners can sync their state again
- */
- Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
- if (pThis->pDrv)
- {
- pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
- if (uVersion >= 10)
- pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
- /*fVisible=*/!!pThis->fHostCursorRequested,
- /*fAlpha=*/false,
- /*xHot=*/0, /*yHot=*/0,
- /*cx=*/0, /*cy=*/0,
- /*pvShape=*/NULL);
- }
- if (pThis->fu32AdditionsOk)
- {
- vmmdevLogGuestOsInfo(&pThis->guestInfo);
- if (pThis->pDrv)
- {
- if (pThis->guestInfo2.uFullVersion && pThis->pDrv->pfnUpdateGuestInfo2)
- pThis->pDrv->pfnUpdateGuestInfo2(pThis->pDrv, pThis->guestInfo2.uFullVersion, pThis->guestInfo2.szName,
- pThis->guestInfo2.uRevision, pThis->guestInfo2.fFeatures);
- if (pThis->pDrv->pfnUpdateGuestInfo)
- pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
- if (pThis->pDrv->pfnUpdateGuestStatus)
- {
- for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++) /* ascending order! */
- if ( pThis->aFacilityStatuses[i].enmStatus != VBoxGuestFacilityStatus_Inactive
- || !pThis->aFacilityStatuses[i].fFixed)
- pThis->pDrv->pfnUpdateGuestStatus(pThis->pDrv,
- pThis->aFacilityStatuses[i].enmFacility,
- (uint16_t)pThis->aFacilityStatuses[i].enmStatus,
- pThis->aFacilityStatuses[i].fFlags,
- &pThis->aFacilityStatuses[i].TimeSpecTS);
- }
- }
- }
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
- pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
- return VINF_SUCCESS;
- }
- /**
- * Load state done callback. Notify guest of restore event.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param pSSM The handle to the saved state.
- */
- static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
- {
- RT_NOREF1(pSSM);
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
- #ifdef VBOX_WITH_HGCM
- int rc = vmmdevHGCMLoadStateDone(pThis);
- AssertLogRelRCReturn(rc, rc);
- #endif /* VBOX_WITH_HGCM */
- /* Reestablish the acceleration status. */
- if ( pThis->u32VideoAccelEnabled
- && pThis->pDrv)
- {
- pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, !!pThis->u32VideoAccelEnabled, &pThis->pVMMDevRAMR3->vbvaMemory);
- }
- VMMDevNotifyGuest(pThis, VMMDEV_EVENT_RESTORED);
- return VINF_SUCCESS;
- }
- /* -=-=-=-=- PDMDEVREG -=-=-=-=- */
- /**
- * (Re-)initializes the MMIO2 data.
- *
- * @param pThis Pointer to the VMMDev instance data.
- */
- static void vmmdevInitRam(PVMMDEV pThis)
- {
- memset(pThis->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
- pThis->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
- pThis->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
- }
- /**
- * @interface_method_impl{PDMDEVREG,pfnReset}
- */
- static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
- {
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
- PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- /*
- * Reset the mouse integration feature bits
- */
- if (pThis->mouseCapabilities & VMMDEV_MOUSE_GUEST_MASK)
- {
- pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
- /* notify the connector */
- Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
- pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
- }
- pThis->fHostCursorRequested = false;
- pThis->hypervisorSize = 0;
- /* re-initialize the VMMDev memory */
- if (pThis->pVMMDevRAMR3)
- vmmdevInitRam(pThis);
- /* credentials have to go away (by default) */
- if (!pThis->fKeepCredentials)
- {
- memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- }
- memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- /* Reset means that additions will report again. */
- const bool fVersionChanged = pThis->fu32AdditionsOk
- || pThis->guestInfo.interfaceVersion
- || pThis->guestInfo.osType != VBOXOSTYPE_Unknown;
- if (fVersionChanged)
- Log(("vmmdevReset: fu32AdditionsOk=%d additionsVersion=%x osType=%#x\n",
- pThis->fu32AdditionsOk, pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
- pThis->fu32AdditionsOk = false;
- memset (&pThis->guestInfo, 0, sizeof (pThis->guestInfo));
- RT_ZERO(pThis->guestInfo2);
- const bool fCapsChanged = pThis->guestCaps != 0; /* Report transition to 0. */
- pThis->guestCaps = 0;
- /* Clear facilities. No need to tell Main as it will get a
- pfnUpdateGuestInfo callback. */
- RTTIMESPEC TimeStampNow;
- RTTimeNow(&TimeStampNow);
- uint32_t iFacility = pThis->cFacilityStatuses;
- while (iFacility-- > 0)
- {
- pThis->aFacilityStatuses[iFacility].enmStatus = VBoxGuestFacilityStatus_Inactive;
- pThis->aFacilityStatuses[iFacility].TimeSpecTS = TimeStampNow;
- }
- /* clear pending display change request. */
- for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
- {
- DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
- memset (&pRequest->lastReadDisplayChangeRequest, 0, sizeof (pRequest->lastReadDisplayChangeRequest));
- }
- pThis->displayChangeData.iCurrentMonitor = 0;
- pThis->displayChangeData.fGuestSentChangeEventAck = false;
- /* disable seamless mode */
- pThis->fLastSeamlessEnabled = false;
- /* disabled memory ballooning */
- pThis->cMbMemoryBalloonLast = 0;
- /* disabled statistics updating */
- pThis->u32LastStatIntervalSize = 0;
- #ifdef VBOX_WITH_HGCM
- /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled. */
- pThis->u32HGCMEnabled = 0;
- #endif
- /*
- * Deactive heartbeat.
- */
- if (pThis->fHeartbeatActive)
- {
- TMTimerStop(pThis->pFlatlinedTimer);
- pThis->fFlatlined = false;
- pThis->fHeartbeatActive = true;
- }
- /*
- * Clear the event variables.
- *
- * XXX By design we should NOT clear pThis->u32HostEventFlags because it is designed
- * that way so host events do not depend on guest resets. However, the pending
- * event flags actually _were_ cleared since ages so we mask out events from
- * clearing which we really need to survive the reset. See xtracker 5767.
- */
- pThis->u32HostEventFlags &= VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
- pThis->u32GuestFilterMask = 0;
- pThis->u32NewGuestFilterMask = 0;
- pThis->fNewGuestFilterMask = 0;
- /*
- * Call the update functions as required.
- */
- if (fVersionChanged && pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
- pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
- if (fCapsChanged && pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
- pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
- /*
- * Generate a unique session id for this VM; it will be changed for each start, reset or restore.
- * This can be used for restore detection inside the guest.
- */
- pThis->idSession = ASMReadTSC();
- PDMCritSectLeave(&pThis->CritSect);
- }
- /**
- * @interface_method_impl{PDMDEVREG,pfnRelocate}
- */
- static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
- {
- NOREF(pDevIns);
- NOREF(offDelta);
- }
- /**
- * @interface_method_impl{PDMDEVREG,pfnDestruct}
- */
- static DECLCALLBACK(int) vmmdevDestruct(PPDMDEVINS pDevIns)
- {
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
- /*
- * Wipe and free the credentials.
- */
- if (pThis->pCredentials)
- {
- RTMemWipeThoroughly(pThis->pCredentials, sizeof(*pThis->pCredentials), 10);
- RTMemFree(pThis->pCredentials);
- pThis->pCredentials = NULL;
- }
- #ifdef VBOX_WITH_HGCM
- vmmdevHGCMDestroy(pThis);
- RTCritSectDelete(&pThis->critsectHGCMCmdList);
- #endif
- #ifndef VBOX_WITHOUT_TESTING_FEATURES
- /*
- * Clean up the testing device.
- */
- vmmdevTestingTerminate(pDevIns);
- #endif
- return VINF_SUCCESS;
- }
- /**
- * @interface_method_impl{PDMDEVREG,pfnConstruct}
- */
- static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
- {
- PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
- int rc;
- Assert(iInstance == 0);
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
- /*
- * Initialize data (most of it anyway).
- */
- /* Save PDM device instance data for future reference. */
- pThis->pDevIns = pDevIns;
- /* PCI vendor, just a free bogus value */
- PCIDevSetVendorId(&pThis->PciDev, 0x80ee);
- /* device ID */
- PCIDevSetDeviceId(&pThis->PciDev, 0xcafe);
- /* class sub code (other type of system peripheral) */
- PCIDevSetClassSub(&pThis->PciDev, 0x80);
- /* class base code (base system peripheral) */
- PCIDevSetClassBase(&pThis->PciDev, 0x08);
- /* header type */
- PCIDevSetHeaderType(&pThis->PciDev, 0x00);
- /* interrupt on pin 0 */
- PCIDevSetInterruptPin(&pThis->PciDev, 0x01);
- RTTIMESPEC TimeStampNow;
- RTTimeNow(&TimeStampNow);
- vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxGuestDriver, true /*fFixed*/, &TimeStampNow);
- vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxService, true /*fFixed*/, &TimeStampNow);
- vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxTrayClient, true /*fFixed*/, &TimeStampNow);
- vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Seamless, true /*fFixed*/, &TimeStampNow);
- vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Graphics, true /*fFixed*/, &TimeStampNow);
- Assert(pThis->cFacilityStatuses == 5);
- /*
- * Interfaces
- */
- /* IBase */
- pThis->IBase.pfnQueryInterface = vmmdevPortQueryInterface;
- /* VMMDev port */
- pThis->IPort.pfnQueryAbsoluteMouse = vmmdevIPort_QueryAbsoluteMouse;
- pThis->IPort.pfnSetAbsoluteMouse = vmmdevIPort_SetAbsoluteMouse ;
- pThis->IPort.pfnQueryMouseCapabilities = vmmdevIPort_QueryMouseCapabilities;
- pThis->IPort.pfnUpdateMouseCapabilities = vmmdevIPort_UpdateMouseCapabilities;
- pThis->IPort.pfnRequestDisplayChange = vmmdevIPort_RequestDisplayChange;
- pThis->IPort.pfnSetCredentials = vmmdevIPort_SetCredentials;
- pThis->IPort.pfnVBVAChange = vmmdevIPort_VBVAChange;
- pThis->IPort.pfnRequestSeamlessChange = vmmdevIPort_RequestSeamlessChange;
- pThis->IPort.pfnSetMemoryBalloon = vmmdevIPort_SetMemoryBalloon;
- pThis->IPort.pfnSetStatisticsInterval = vmmdevIPort_SetStatisticsInterval;
- pThis->IPort.pfnVRDPChange = vmmdevIPort_VRDPChange;
- pThis->IPort.pfnCpuHotUnplug = vmmdevIPort_CpuHotUnplug;
- pThis->IPort.pfnCpuHotPlug = vmmdevIPort_CpuHotPlug;
- /* Shared folder LED */
- pThis->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
- pThis->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
- #ifdef VBOX_WITH_HGCM
- /* HGCM port */
- pThis->IHGCMPort.pfnCompleted = hgcmCompleted;
- #endif
- pThis->pCredentials = (VMMDEVCREDS *)RTMemAllocZ(sizeof(*pThis->pCredentials));
- if (!pThis->pCredentials)
- return VERR_NO_MEMORY;
- /*
- * Validate and read the configuration.
- */
- PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
- "GetHostTimeDisabled|"
- "BackdoorLogDisabled|"
- "KeepCredentials|"
- "HeapEnabled|"
- "RZEnabled|"
- "GuestCoreDumpEnabled|"
- "GuestCoreDumpDir|"
- "GuestCoreDumpCount|"
- "HeartbeatInterval|"
- "HeartbeatTimeout|"
- "TestingEnabled|"
- "TestingMMIO|"
- "TestintXmlOutputFile"
- ,
- "");
- rc = CFGMR3QueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
- rc = CFGMR3QueryBoolDef(pCfg, "BackdoorLogDisabled", &pThis->fBackdoorLogDisabled, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
- rc = CFGMR3QueryBoolDef(pCfg, "KeepCredentials", &pThis->fKeepCredentials, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
- rc = CFGMR3QueryBoolDef(pCfg, "HeapEnabled", &pThis->fHeapEnabled, true);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"HeapEnabled\" as a boolean"));
- rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &pThis->fRZEnabled, true);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"RZEnabled\" as a boolean"));
- rc = CFGMR3QueryBoolDef(pCfg, "GuestCoreDumpEnabled", &pThis->fGuestCoreDumpEnabled, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"GuestCoreDumpEnabled\" as a boolean"));
- char *pszGuestCoreDumpDir = NULL;
- rc = CFGMR3QueryStringAllocDef(pCfg, "GuestCoreDumpDir", &pszGuestCoreDumpDir, "");
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"GuestCoreDumpDir\" as a string"));
- RTStrCopy(pThis->szGuestCoreDumpDir, sizeof(pThis->szGuestCoreDumpDir), pszGuestCoreDumpDir);
- MMR3HeapFree(pszGuestCoreDumpDir);
- rc = CFGMR3QueryU32Def(pCfg, "GuestCoreDumpCount", &pThis->cGuestCoreDumps, 3);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"GuestCoreDumpCount\" as a 32-bit unsigned integer"));
- rc = CFGMR3QueryU64Def(pCfg, "HeartbeatInterval", &pThis->cNsHeartbeatInterval, VMMDEV_HEARTBEAT_DEFAULT_INTERVAL);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"HeartbeatInterval\" as a 64-bit unsigned integer"));
- if (pThis->cNsHeartbeatInterval < RT_NS_100MS / 2)
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Heartbeat interval \"HeartbeatInterval\" too small"));
- rc = CFGMR3QueryU64Def(pCfg, "HeartbeatTimeout", &pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval * 2);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"HeartbeatTimeout\" as a 64-bit unsigned integer"));
- if (pThis->cNsHeartbeatTimeout < RT_NS_100MS)
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" too small"));
- if (pThis->cNsHeartbeatTimeout <= pThis->cNsHeartbeatInterval + RT_NS_10MS)
- return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
- N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" value (%'ull ns) is too close to the interval (%'ull ns)"),
- pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval);
- #ifndef VBOX_WITHOUT_TESTING_FEATURES
- rc = CFGMR3QueryBoolDef(pCfg, "TestingEnabled", &pThis->fTestingEnabled, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"TestingEnabled\" as a boolean"));
- rc = CFGMR3QueryBoolDef(pCfg, "TestingMMIO", &pThis->fTestingMMIO, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"TestingMMIO\" as a boolean"));
- rc = CFGMR3QueryStringAllocDef(pCfg, "TestintXmlOutputFile", &pThis->pszTestingXmlOutput, NULL);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestintXmlOutputFile\" as a string"));
- /** @todo image-to-load-filename? */
- #endif
- pThis->cbGuestRAM = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
- /*
- * We do our own locking entirely. So, install NOP critsect for the device
- * and create our own critsect for use where it really matters (++).
- */
- rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
- AssertRCReturn(rc, rc);
- rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev#%u", iInstance);
- AssertRCReturn(rc, rc);
- /*
- * Register the backdoor logging port
- */
- rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog,
- NULL, NULL, NULL, "VMMDev backdoor logging");
- AssertRCReturn(rc, rc);
- #ifdef VMMDEV_WITH_ALT_TIMESYNC
- /*
- * Alternative timesync source.
- *
- * This was orignally added for creating a simple time sync service in an
- * OpenBSD guest without requiring VBoxGuest and VBoxService to be ported
- * first. We keep it in case it comes in handy.
- */
- rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL,
- vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead,
- NULL, NULL, "VMMDev timesync backdoor");
- AssertRCReturn(rc, rc);
- #endif
- /*
- * Register the PCI device.
- */
- rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
- if (RT_FAILURE(rc))
- return rc;
- if (pThis->PciDev.uDevFn != 32 || iInstance != 0)
- Log(("!!WARNING!!: pThis->PciDev.uDevFn=%d (ignore if testcase or no started by Main)\n", pThis->PciDev.uDevFn));
- rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
- if (RT_FAILURE(rc))
- return rc;
- rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
- if (RT_FAILURE(rc))
- return rc;
- if (pThis->fHeapEnabled)
- {
- rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, VMMDEV_HEAP_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH, vmmdevIORAMRegionMap);
- if (RT_FAILURE(rc))
- return rc;
- }
- /*
- * Allocate and initialize the MMIO2 memory.
- */
- rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->PciDev, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0 /*fFlags*/,
- (void **)&pThis->pVMMDevRAMR3, "VMMDev");
- if (RT_FAILURE(rc))
- return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
- N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
- vmmdevInitRam(pThis);
- if (pThis->fHeapEnabled)
- {
- rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->PciDev, 2 /*iRegion*/, VMMDEV_HEAP_SIZE, 0 /*fFlags*/,
- (void **)&pThis->pVMMDevHeapR3, "VMMDev Heap");
- if (RT_FAILURE(rc))
- return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
- N_("Failed to allocate %u bytes of memory for the VMM device heap"), PAGE_SIZE);
- /* Register the memory area with PDM so HM can access it before it's mapped. */
- rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
- AssertLogRelRCReturn(rc, rc);
- }
- #ifndef VBOX_WITHOUT_TESTING_FEATURES
- /*
- * Initialize testing.
- */
- rc = vmmdevTestingInitialize(pDevIns);
- if (RT_FAILURE(rc))
- return rc;
- #endif
- /*
- * Get the corresponding connector interface
- */
- rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "VMM Driver Port");
- if (RT_SUCCESS(rc))
- {
- pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIVMMDEVCONNECTOR);
- AssertMsgReturn(pThis->pDrv, ("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
- #ifdef VBOX_WITH_HGCM
- pThis->pHGCMDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHGCMCONNECTOR);
- if (!pThis->pHGCMDrv)
- {
- Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Rrc\n", rc));
- /* this is not actually an error, just means that there is no support for HGCM */
- }
- #endif
- /* Query the initial balloon size. */
- AssertPtr(pThis->pDrv->pfnQueryBalloonSize);
- rc = pThis->pDrv->pfnQueryBalloonSize(pThis->pDrv, &pThis->cMbMemoryBalloon);
- AssertRC(rc);
- Log(("Initial balloon size %x\n", pThis->cMbMemoryBalloon));
- }
- else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- {
- Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
- rc = VINF_SUCCESS;
- }
- else
- AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Rrc\n", rc), rc);
- /*
- * Attach status driver for shared folders (optional).
- */
- PPDMIBASE pBase;
- rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
- if (RT_SUCCESS(rc))
- pThis->SharedFolders.pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
- else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
- {
- AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
- return rc;
- }
- /*
- * Register saved state and init the HGCM CmdList critsect.
- */
- rc = PDMDevHlpSSMRegisterEx(pDevIns, VMMDEV_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
- NULL, vmmdevLiveExec, NULL,
- NULL, vmmdevSaveExec, NULL,
- NULL, vmmdevLoadExec, vmmdevLoadStateDone);
- AssertRCReturn(rc, rc);
- /*
- * Create heartbeat checking timer.
- */
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vmmDevHeartbeatFlatlinedTimer, pThis,
- TMTIMER_FLAGS_NO_CRIT_SECT, "Heartbeat flatlined", &pThis->pFlatlinedTimer);
- AssertRCReturn(rc, rc);
- #ifdef VBOX_WITH_HGCM
- pThis->pHGCMCmdList = NULL;
- rc = RTCritSectInit(&pThis->critsectHGCMCmdList);
- AssertRCReturn(rc, rc);
- pThis->u32HGCMEnabled = 0;
- #endif /* VBOX_WITH_HGCM */
- /*
- * In this version of VirtualBox the GUI checks whether "needs host cursor"
- * changes.
- */
- pThis->mouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
- PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Memory balloon size", "/Devices/VMMDev/BalloonChunks");
- /*
- * Generate a unique session id for this VM; it will be changed for each
- * start, reset or restore. This can be used for restore detection inside
- * the guest.
- */
- pThis->idSession = ASMReadTSC();
- return rc;
- }
- /**
- * The device registration structure.
- */
- extern "C" const PDMDEVREG g_DeviceVMMDev =
- {
- /* u32Version */
- PDM_DEVREG_VERSION,
- /* szName */
- "VMMDev",
- /* szRCMod */
- "VBoxDDRC.rc",
- /* szR0Mod */
- "VBoxDDR0.r0",
- /* pszDescription */
- "VirtualBox VMM Device\n",
- /* fFlags */
- PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
- /* fClass */
- PDM_DEVREG_CLASS_VMM_DEV,
- /* cMaxInstances */
- 1,
- /* cbInstance */
- sizeof(VMMDevState),
- /* pfnConstruct */
- vmmdevConstruct,
- /* pfnDestruct */
- vmmdevDestruct,
- /* pfnRelocate */
- vmmdevRelocate,
- /* pfnMemSetup */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- vmmdevReset,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnQueryInterface. */
- NULL,
- /* pfnInitComplete */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32VersionEnd */
- PDM_DEVREG_VERSION
- };
- #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Advertisement
Add Comment
Please, Sign In to add comment