summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/VMMDev
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/VMMDev')
-rw-r--r--src/VBox/Devices/VMMDev/VMMDev.cpp4122
-rw-r--r--src/VBox/Devices/VMMDev/VMMDevHGCM.cpp465
-rw-r--r--src/VBox/Devices/VMMDev/VMMDevHGCM.h2
-rw-r--r--src/VBox/Devices/VMMDev/VMMDevState.h72
-rw-r--r--src/VBox/Devices/VMMDev/VMMDevTesting.cpp152
-rw-r--r--src/VBox/Devices/VMMDev/VMMDevTesting.h3
6 files changed, 2745 insertions, 2071 deletions
diff --git a/src/VBox/Devices/VMMDev/VMMDev.cpp b/src/VBox/Devices/VMMDev/VMMDev.cpp
index e4328151..918b5b01 100644
--- a/src/VBox/Devices/VMMDev/VMMDev.cpp
+++ b/src/VBox/Devices/VMMDev/VMMDev.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -19,9 +19,7 @@
/*******************************************************************************
* 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>
@@ -61,9 +59,6 @@
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-#define PCIDEV_2_VMMDEVSTATE(pPciDev) ( (VMMDevState *)(pPciDev) )
-#define VMMDEVSTATE_2_DEVINS(pVMMDevState) ( (pVMMDevState)->pDevIns )
-
#define VBOX_GUEST_INTERFACE_VERSION_1_03(s) \
( RT_HIWORD((s)->guestInfo.interfaceVersion) == 1 \
&& RT_LOWORD((s)->guestInfo.interfaceVersion) == 3 )
@@ -98,299 +93,264 @@
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-/* Whenever host wants to inform guest about something
- * an IRQ notification will be raised.
+/** @page pg_vmmdev VMMDev
+ *
+ * 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
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * This seems to be fast method. It requires only one context switch for an
+ * event processing.
*
*/
-static void vmmdevSetIRQ_Legacy_EMT (VMMDevState *pVMMDevState)
+
+/* -=-=-=-=- Misc Helpers -=-=-=-=- */
+
+
+/**
+ * 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 (!pVMMDevState->fu32AdditionsOk)
+ if (!pThis->fu32AdditionsOk)
{
Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
return;
}
- uint32_t u32IRQLevel = 0;
-
/* Filter unsupported events */
- uint32_t u32EventFlags =
- pVMMDevState->u32HostEventFlags
- & pVMMDevState->pVMMDevRAMR3->V.V1_03.u32GuestEventMask;
+ uint32_t u32EventFlags = pThis->u32HostEventFlags
+ & pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask;
- Log(("vmmdevSetIRQ: u32EventFlags = 0x%08X, "
- "pVMMDevState->u32HostEventFlags = 0x%08X, "
- "pVMMDevState->pVMMDevRAMR3->u32GuestEventMask = 0x%08X\n",
- u32EventFlags,
- pVMMDevState->u32HostEventFlags,
- pVMMDevState->pVMMDevRAMR3->V.V1_03.u32GuestEventMask));
+ Log(("vmmdevSetIRQ: u32EventFlags=%#010x, u32HostEventFlags=%#010x, u32GuestEventMask=%#010x.\n",
+ u32EventFlags, pThis->u32HostEventFlags, pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask));
/* Move event flags to VMMDev RAM */
- pVMMDevState->pVMMDevRAMR3->V.V1_03.u32HostEvents = u32EventFlags;
+ pThis->pVMMDevRAMR3->V.V1_03.u32HostEvents = u32EventFlags;
+ uint32_t u32IRQLevel = 0;
if (u32EventFlags)
{
/* Clear host flags which will be delivered to guest. */
- pVMMDevState->u32HostEventFlags &= ~u32EventFlags;
- Log(("vmmdevSetIRQ: pVMMDevState->u32HostEventFlags = 0x%08X\n",
- pVMMDevState->u32HostEventFlags));
+ pThis->u32HostEventFlags &= ~u32EventFlags;
+ Log(("vmmdevSetIRQ: u32HostEventFlags=%#010x\n", pThis->u32HostEventFlags));
u32IRQLevel = 1;
}
- /* Set IRQ level for pin 0 */
+ /* Set IRQ level for pin 0 (see NoWait comment in vmmdevMaybeSetIRQ). */
/** @todo make IRQ pin configurable, at least a symbolic constant */
- PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
+ PPDMDEVINS pDevIns = pThis->pDevIns;
PDMDevHlpPCISetIrqNoWait(pDevIns, 0, u32IRQLevel);
Log(("vmmdevSetIRQ: IRQ set %d\n", u32IRQLevel));
}
-static void vmmdevMaybeSetIRQ_EMT (VMMDevState *pVMMDevState)
+/**
+ * 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)
{
- PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS (pVMMDevState);
-
- Log3(("vmmdevMaybeSetIRQ_EMT: u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
- pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
+ Log3(("vmmdevMaybeSetIRQ: u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
+ pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
- if (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask)
+ if (pThis->u32HostEventFlags & pThis->u32GuestFilterMask)
{
- pVMMDevState->pVMMDevRAMR3->V.V1_04.fHaveEvents = true;
- PDMDevHlpPCISetIrqNoWait (pDevIns, 0, 1);
- Log3(("vmmdevMaybeSetIRQ_EMT: IRQ set.\n"));
+ /*
+ * 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"));
}
}
-static void vmmdevNotifyGuest_EMT (VMMDevState *pVMMDevState, uint32_t u32EventMask)
+/**
+ * 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(("VMMDevNotifyGuest_EMT: u32EventMask = 0x%08X.\n", u32EventMask));
+ Log3(("vmmdevNotifyGuestWorker: fAddEvents=%#010x.\n", fAddEvents));
+ Assert(PDMCritSectIsOwner(&pThis->CritSect));
- if (VBOX_GUEST_INTERFACE_VERSION_1_03 (pVMMDevState))
+ if (VBOX_GUEST_INTERFACE_VERSION_1_03(pThis))
{
- Log3(("VMMDevNotifyGuest_EMT: Old additions detected.\n"));
+ Log3(("vmmdevNotifyGuestWorker: Old additions detected.\n"));
- pVMMDevState->u32HostEventFlags |= u32EventMask;
- vmmdevSetIRQ_Legacy_EMT (pVMMDevState);
+ pThis->u32HostEventFlags |= fAddEvents;
+ vmmdevSetIRQ_Legacy(pThis);
}
else
{
- Log3(("VMMDevNotifyGuest_EMT: New additions detected.\n"));
+ Log3(("vmmdevNotifyGuestWorker: New additions detected.\n"));
- if (!pVMMDevState->fu32AdditionsOk)
+ if (!pThis->fu32AdditionsOk)
{
- pVMMDevState->u32HostEventFlags |= u32EventMask;
- Log(("vmmdevNotifyGuest_EMT: IRQ is not generated, guest has not yet reported to us.\n"));
+ pThis->u32HostEventFlags |= fAddEvents;
+ Log(("vmmdevNotifyGuestWorker: IRQ is not generated, guest has not yet reported to us.\n"));
return;
}
- const bool fHadEvents =
- (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
+ const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
- Log3(("VMMDevNotifyGuest_EMT: fHadEvents = %d, u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
- fHadEvents, pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
+ Log3(("vmmdevNotifyGuestWorker: fHadEvents=%d, u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
+ fHadEvents, pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
- pVMMDevState->u32HostEventFlags |= u32EventMask;
+ pThis->u32HostEventFlags |= fAddEvents;
if (!fHadEvents)
- vmmdevMaybeSetIRQ_EMT (pVMMDevState);
+ vmmdevMaybeSetIRQ(pThis);
}
}
-void VMMDevCtlSetGuestFilterMask (VMMDevState *pVMMDevState,
- uint32_t u32OrMask,
- uint32_t u32NotMask)
-{
- PDMCritSectEnter(&pVMMDevState->CritSect, VERR_SEM_BUSY);
- const bool fHadEvents =
- (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
- Log(("VMMDevCtlSetGuestFilterMask: u32OrMask = 0x%08X, u32NotMask = 0x%08X, fHadEvents = %d.\n", u32OrMask, u32NotMask, fHadEvents));
- if (fHadEvents)
- {
- if (!pVMMDevState->fNewGuestFilterMask)
- pVMMDevState->u32NewGuestFilterMask = pVMMDevState->u32GuestFilterMask;
+/* -=-=-=-=- Interfaces shared with VMMDevHGCM.cpp -=-=-=-=- */
- pVMMDevState->u32NewGuestFilterMask |= u32OrMask;
- pVMMDevState->u32NewGuestFilterMask &= ~u32NotMask;
- pVMMDevState->fNewGuestFilterMask = true;
- }
- else
- {
- pVMMDevState->u32GuestFilterMask |= u32OrMask;
- pVMMDevState->u32GuestFilterMask &= ~u32NotMask;
- vmmdevMaybeSetIRQ_EMT (pVMMDevState);
- }
- PDMCritSectLeave(&pVMMDevState->CritSect);
-}
-
-void VMMDevNotifyGuest (VMMDevState *pVMMDevState, uint32_t u32EventMask)
+/**
+ * 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)
{
- PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
-
- Log3(("VMMDevNotifyGuest: u32EventMask = 0x%08X.\n", u32EventMask));
+ Log3(("VMMDevNotifyGuest: fAddEvents=%#010x\n", fAddEvents));
/*
* Drop notifications if the VM is not running yet/anymore.
*/
- VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
+ VMSTATE enmVMState = PDMDevHlpVMState(pThis->pDevIns);
if ( enmVMState != VMSTATE_RUNNING
&& enmVMState != VMSTATE_RUNNING_LS)
return;
- PDMCritSectEnter(&pVMMDevState->CritSect, VERR_SEM_BUSY);
- /* No need to wait for the completion of this request. It is a notification
- * about something, which has already happened.
- */
- vmmdevNotifyGuest_EMT(pVMMDevState, u32EventMask);
- PDMCritSectLeave(&pVMMDevState->CritSect);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
+ vmmdevNotifyGuestWorker(pThis, fAddEvents);
+ PDMCritSectLeave(&pThis->CritSect);
}
/**
- * Port I/O Handler for OUT operations.
+ * Code shared by VMMDevReq_CtlGuestFilterMask and HGCM for controlling the
+ * events the guest are interested in.
*
- * @returns VBox status code.
+ * @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.
*
- * @param pDevIns The device instance.
- * @param pvUser User argument - ignored.
- * @param uPort Port number used for the IN operation.
- * @param u32 The value to output.
- * @param cb The value size in bytes.
+ * @remarks When HGCM will automatically enable VMMDEV_EVENT_HGCM when the guest
+ * starts submitting HGCM requests. Otherwise, the events are
+ * controlled by the guest.
*/
-static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
+void VMMDevCtlSetGuestFilterMask(PVMMDEV pThis, uint32_t fOrMask, uint32_t fNotMask)
{
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- if (!pThis->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
- {
+ const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
- /* The raw version. */
- switch (u32)
- {
- case '\r': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
- case '\n': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
- case '\t': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
- default: LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: %c (%02x)\n", u32, u32)); break;
- }
+ Log(("VMMDevCtlSetGuestFilterMask: fOrMask=%#010x, u32NotMask=%#010x, fHadEvents=%d.\n", fOrMask, fNotMask, fHadEvents));
+ if (fHadEvents)
+ {
+ if (!pThis->fNewGuestFilterMask)
+ pThis->u32NewGuestFilterMask = pThis->u32GuestFilterMask;
- /* The readable, buffered version. */
- if (u32 == '\n' || u32 == '\r')
- {
- pThis->szMsg[pThis->iMsg] = '\0';
- if (pThis->iMsg)
- LogRelIt(LOG_REL_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("Guest Log: %s\n", pThis->szMsg));
- pThis->iMsg = 0;
- }
- else
- {
- if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
- {
- pThis->szMsg[pThis->iMsg] = '\0';
- LogRelIt(LOG_REL_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("Guest Log: %s\n", pThis->szMsg));
- pThis->iMsg = 0;
- }
- pThis->szMsg[pThis->iMsg] = (char )u32;
- pThis->szMsg[++pThis->iMsg] = '\0';
- }
+ pThis->u32NewGuestFilterMask |= fOrMask;
+ pThis->u32NewGuestFilterMask &= ~fNotMask;
+ pThis->fNewGuestFilterMask = true;
}
- return VINF_SUCCESS;
-}
-
-#ifdef TIMESYNC_BACKDOOR
-/**
- * Port I/O Handler for OUT operations.
- *
- * @returns VBox status code.
- *
- * @param pDevIns The device instance.
- * @param pvUser User argument - ignored.
- * @param uPort Port number used for the IN operation.
- * @param u32 The value to output.
- * @param cb The value size in bytes.
- */
-static DECLCALLBACK(int) vmmdevTimesyncBackdoorWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
-{
- NOREF(pvUser);
- if (cb == 4)
+ else
{
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
- switch (u32)
- {
- case 0:
- pThis->fTimesyncBackdoorLo = false;
- break;
- case 1:
- pThis->fTimesyncBackdoorLo = true;
- }
- return VINF_SUCCESS;
-
+ pThis->u32GuestFilterMask |= fOrMask;
+ pThis->u32GuestFilterMask &= ~fNotMask;
+ vmmdevMaybeSetIRQ(pThis);
}
- return VINF_SUCCESS;
+
+ PDMCritSectLeave(&pThis->CritSect);
}
+
+
+/* -=-=-=-=- Request processing functions. -=-=-=-=- */
+
/**
- * Port I/O Handler for backdoor timesync IN operations.
- *
- * @returns VBox status code.
+ * Handles VMMDevReq_ReportGuestInfo.
*
- * @param pDevIns The device instance.
- * @param pvUser User argument - ignored.
- * @param uPort Port number used for the IN operation.
- * @param pu32 Where to store the result.
- * @param cb Number of bytes read.
+ * @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 DECLCALLBACK(int) vmmdevTimesyncBackdoorRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
+static int vmmdevReqHandler_ReportGuestInfo(PVMMDEV pThis, VMMDevRequestHeader *pRequestHeader)
{
- int rc;
- NOREF(pvUser);
- if (cb == 4)
+ 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)
{
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
- RTTIMESPEC now;
+ /* Make a copy of supplied information. */
+ pThis->guestInfo = *pInfo;
- if (pThis->fTimesyncBackdoorLo)
- *pu32 = (uint32_t)pThis->hostTime;
- else
- {
- pThis->hostTime = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &now));
- *pu32 = (uint32_t)(pThis->hostTime >> 32);
- }
- rc = VINF_SUCCESS;
+ /* Check additions interface version. */
+ pThis->fu32AdditionsOk = VBOX_GUEST_INTERFACE_VERSION_OK(pThis->guestInfo.interfaceVersion);
+
+ LogRel(("Guest Additions information report: Interface = 0x%08X osType = 0x%08X\n",
+ pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
+
+ if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
+ pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
}
- else
- rc = VERR_IOM_IOPORT_UNUSED;
- return rc;
+
+ 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;
}
-#endif /* TIMESYNC_BACKDOOR */
+
/**
* Validates a publisher tag.
@@ -439,17 +399,18 @@ static bool vmmdevReqIsValidBuildTag(const char *pszTag)
return rc == VINF_SUCCESS;
}
+
/**
* Handles VMMDevReq_ReportGuestInfo2.
*
* @returns VBox status code that the guest should see.
* @param pThis The VMMDev instance data.
- * @param pRequestHeader The header of the request to handle.
+ * @param pReqHdr The header of the request to handle.
*/
-static int vmmdevReqHandler_ReportGuestInfo2(VMMDevState *pThis, VMMDevRequestHeader *pRequestHeader)
+static int vmmdevReqHandler_ReportGuestInfo2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
{
- AssertMsgReturn(pRequestHeader->size == sizeof(VMMDevReportGuestInfo2), ("%u\n", pRequestHeader->size), VERR_INVALID_PARAMETER);
- VBoxGuestInfo2 const *pInfo2 = &((VMMDevReportGuestInfo2 *)pRequestHeader)->guestInfo;
+ AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReportGuestInfo2), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
+ VBoxGuestInfo2 const *pInfo2 = &((VMMDevReportGuestInfo2 *)pReqHdr)->guestInfo;
LogRel(("Guest Additions information report: Version %d.%d.%d r%d '%.*s'\n",
pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild,
@@ -541,6 +502,7 @@ static int vmmdevReqHandler_ReportGuestInfo2(VMMDevState *pThis, VMMDevRequestHe
return VINF_SUCCESS;
}
+
/**
* Allocates a new facility status entry, initializing it to inactive.
*
@@ -553,7 +515,7 @@ static int vmmdevReqHandler_ReportGuestInfo2(VMMDevState *pThis, VMMDevRequestHe
* @param pTimeSpecNow Optionally giving the entry timestamp to use (ctor).
*/
static PVMMDEVFACILITYSTATUSENTRY
-vmmdevAllocFacilityStatusEntry(VMMDevState *pThis, uint32_t uFacility, bool fFixed, PCRTTIMESPEC pTimeSpecNow)
+vmmdevAllocFacilityStatusEntry(PVMMDEV pThis, uint32_t uFacility, bool fFixed, PCRTTIMESPEC pTimeSpecNow)
{
/* If full, expunge one inactive entry. */
if (pThis->cFacilityStatuses == RT_ELEMENTS(pThis->aFacilityStatuses))
@@ -605,9 +567,9 @@ vmmdevAllocFacilityStatusEntry(VMMDevState *pThis, uint32_t uFacility, bool fFix
RTTimeSpecSetNano(&pThis->aFacilityStatuses[i].TimeSpecTS, 0);
return &pThis->aFacilityStatuses[i];
-
}
+
/**
* Gets a facility status entry, allocating a new one if not already present.
*
@@ -616,7 +578,7 @@ vmmdevAllocFacilityStatusEntry(VMMDevState *pThis, uint32_t uFacility, bool fFix
* @param pThis The VMMDev instance data.
* @param uFacility The facility type code - VBoxGuestFacilityType.
*/
-static PVMMDEVFACILITYSTATUSENTRY vmmdevGetFacilityStatusEntry(VMMDevState *pThis, uint32_t uFacility)
+static PVMMDEVFACILITYSTATUSENTRY vmmdevGetFacilityStatusEntry(PVMMDEV pThis, uint32_t uFacility)
{
/** @todo change to binary search. */
uint32_t i = pThis->cFacilityStatuses;
@@ -630,20 +592,21 @@ static PVMMDEVFACILITYSTATUSENTRY vmmdevGetFacilityStatusEntry(VMMDevState *pThi
return vmmdevAllocFacilityStatusEntry(pThis, uFacility, false /*fFixed*/, NULL);
}
+
/**
* Handles VMMDevReq_ReportGuestStatus.
*
* @returns VBox status code that the guest should see.
* @param pThis The VMMDev instance data.
- * @param pRequestHeader The header of the request to handle.
+ * @param pReqHdr The header of the request to handle.
*/
-static int vmmdevReqHandler_ReportGuestStatus(VMMDevState *pThis, VMMDevRequestHeader *pRequestHeader)
+static int vmmdevReqHandler_ReportGuestStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
{
/*
* Validate input.
*/
- AssertMsgReturn(pRequestHeader->size == sizeof(VMMDevReportGuestStatus), ("%u\n", pRequestHeader->size), VERR_INVALID_PARAMETER);
- VBoxGuestStatus *pStatus = &((VMMDevReportGuestStatus *)pRequestHeader)->guestStatus;
+ 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),
@@ -679,7 +642,7 @@ static int vmmdevReqHandler_ReportGuestStatus(VMMDevState *pThis, VMMDevRequestH
}
pEntry->TimeSpecTS = Now;
- pEntry->uStatus = (uint16_t)pStatus->status;
+ pEntry->uStatus = (uint16_t)pStatus->status; /** @todo r=andy uint16_t vs. 32-bit enum. */
pEntry->fFlags = pStatus->flags;
}
@@ -689,1698 +652,2016 @@ static int vmmdevReqHandler_ReportGuestStatus(VMMDevState *pThis, VMMDevRequestH
return VINF_SUCCESS;
}
-#ifdef VBOX_WITH_PAGE_SHARING
/**
- * Handles VMMDevReq_RegisterSharedModule.
+ * Handles VMMDevReq_ReportGuestUserState.
*
* @returns VBox status code that the guest should see.
- * @param pDevIns The VMMDev device instance.
- * @param pReq Pointer to the request.
+ * @param pThis The VMMDev instance data.
+ * @param pReqHdr The header of the request to handle.
*/
-static int vmmdevReqHandler_RegisterSharedModule(PPDMDEVINS pDevIns, VMMDevSharedModuleRegistrationRequest *pReq)
+static int vmmdevReqHandler_ReportGuestUserState(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
{
/*
- * Basic input validation (more done by GMM).
+ * Validate input.
*/
- 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);
+ AssertMsgReturn(pReqHdr->size >= sizeof(VMMDevReportGuestUserState), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
+ VBoxGuestUserStatus *pStatus = &((VMMDevReportGuestUserState *)pReqHdr)->status;
- AssertReturn(memchr(pReq->szName, '\0', sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
- AssertReturn(memchr(pReq->szVersion, '\0', sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
+ if ( pThis->pDrv
+ && pThis->pDrv->pfnUpdateGuestUserState)
+ {
+ AssertPtr(pStatus);
+
+ if ( pReqHdr->size > _2K
+ || pStatus->cbUser > 256
+ || pStatus->cbDomain > 256
+ || pStatus->cbDetails > _1K) /* Play safe. */
+ {
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /* pyDynamic marks the beginning of the struct's dynamically
+ * allocated data area. */
+ uint8_t *pvDynamic = (uint8_t *)pStatus + RT_OFFSETOF(VBoxGuestUserStatus, szUser);
+ AssertPtr(pvDynamic);
+
+ if (!pStatus->cbUser) /* User name is required. */
+ return VERR_INVALID_PARAMETER;
+ const char *pszUser = (const char *)pvDynamic;
+ AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
+
+ pvDynamic += pStatus->cbUser; /* Advance to next field. */
+ const char *pszDomain = pStatus->cbDomain
+ ? (const char *)pvDynamic : NULL;
+ /* Note: pszDomain can be NULL. */
+
+ pvDynamic += pStatus->cbDomain; /* Advance to next field. */
+ const uint8_t *puDetails = pStatus->cbDetails
+ ? pvDynamic : NULL;
+ /* Note: puDetails can be NULL. */
+
+ pThis->pDrv->pfnUpdateGuestUserState(pThis->pDrv, pszUser, pszDomain,
+ /* State */
+ (uint32_t)pStatus->state,
+ /* State details */
+ puDetails,
+ pStatus->cbDetails);
+ }
- /*
- * Forward the request to the VMM.
- */
- return PGMR3SharedModuleRegister(PDMDevHlpGetVM(pDevIns), pReq->enmGuestOS, pReq->szName, pReq->szVersion,
- pReq->GCBaseAddr, pReq->cbModule, pReq->cRegions, pReq->aRegions);
+ return VINF_SUCCESS;
}
+
/**
- * Handles VMMDevReq_UnregisterSharedModule.
+ * Handles VMMDevReq_ReportGuestCapabilities.
*
* @returns VBox status code that the guest should see.
- * @param pDevIns The VMMDev device instance.
- * @param pReq Pointer to the request.
+ * @param pThis The VMMDev instance data.
+ * @param pReqHdr The header of the request to handle.
*/
-static int vmmdevReqHandler_UnregisterSharedModule(PPDMDEVINS pDevIns, VMMDevSharedModuleUnregistrationRequest *pReq)
+static int vmmdevReqHandler_ReportGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
{
- /*
- * Basic input validation.
- */
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleUnregistrationRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
+ VMMDevReqGuestCapabilities *pReq = (VMMDevReqGuestCapabilities *)pReqHdr;
+ AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- AssertReturn(memchr(pReq->szName, '\0', sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
- AssertReturn(memchr(pReq->szVersion, '\0', sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
+ /* Enable this automatically for guests using the old
+ request to report their capabilities. */
+ /** @todo change this when we next bump the interface version */
+ pReq->caps |= VMMDEV_GUEST_SUPPORTS_GRAPHICS;
+ if (pThis->guestCaps != pReq->caps)
+ {
+ /* make a copy of supplied information */
+ pThis->guestCaps = pReq->caps;
- /*
- * Forward the request to the VMM.
- */
- return PGMR3SharedModuleUnregister(PDMDevHlpGetVM(pDevIns), pReq->szName, pReq->szVersion,
- pReq->GCBaseAddr, pReq->cbModule);
+ LogRel(("Guest Additions capability report: (0x%x) seamless: %s, hostWindowMapping: %s, graphics: %s\n",
+ pReq->caps,
+ pReq->caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
+ pReq->caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
+ pReq->caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
+
+ if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
+ pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pReq->caps);
+ }
+ return VINF_SUCCESS;
}
+
/**
- * Handles VMMDevReq_CheckSharedModules.
+ * Handles VMMDevReq_SetGuestCapabilities.
*
* @returns VBox status code that the guest should see.
- * @param pDevIns The VMMDev device instance.
- * @param pReq Pointer to the request.
+ * @param pThis The VMMDev instance data.
+ * @param pReqHdr The header of the request to handle.
*/
-static int vmmdevReqHandler_CheckSharedModules(PPDMDEVINS pDevIns, VMMDevSharedModuleCheckRequest *pReq)
+static int vmmdevReqHandler_SetGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
{
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleCheckRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
- return PGMR3SharedModuleCheckAll(PDMDevHlpGetVM(pDevIns));
+ VMMDevReqGuestCapabilities2 *pReq = (VMMDevReqGuestCapabilities2 *)pReqHdr;
+ AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
+
+ uint32_t const fOldCaps = pThis->guestCaps; NOREF(fOldCaps);
+ pThis->guestCaps |= pReq->u32OrMask;
+ pThis->guestCaps &= ~pReq->u32NotMask;
+
+ LogRel(("Guest Additions capability report: (%#x -> %#x) seamless: %s, hostWindowMapping: %s, graphics: %s\n",
+ fOldCaps, pThis->guestCaps,
+ pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
+ pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
+ pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
+
+ if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
+ pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
+
+ return VINF_SUCCESS;
}
+
/**
- * Handles VMMDevReq_GetPageSharingStatus.
+ * Handles VMMDevReq_GetMouseStatus.
*
* @returns VBox status code that the guest should see.
* @param pThis The VMMDev instance data.
- * @param pReq Pointer to the request.
+ * @param pReqHdr The header of the request to handle.
*/
-static int vmmdevReqHandler_GetPageSharingStatus(VMMDevState *pThis, VMMDevPageSharingStatusRequest *pReq)
+static int vmmdevReqHandler_GetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *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;
+ 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(("VMMDevReq_GetMouseStatus: features = %#x, xAbs = %d, yAbs = %d\n",
+ pReq->mouseFeatures, pReq->pointerXPos, pReq->pointerYPos));
return VINF_SUCCESS;
}
/**
- * Handles VMMDevReq_DebugIsPageShared.
+ * Handles VMMDevReq_SetMouseStatus.
*
* @returns VBox status code that the guest should see.
- * @param pDevIns The VMMDev device instance.
- * @param pReq Pointer to the request.
+ * @param pThis The VMMDev instance data.
+ * @param pReqHdr The header of the request to handle.
*/
-static int vmmdevReqHandler_DebugIsPageShared(PPDMDEVINS pDevIns, VMMDevPageIsSharedRequest *pReq)
+static int vmmdevReqHandler_SetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
{
- AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageIsSharedRequest),
- ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
+ VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
+ AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
-#ifdef DEBUG
- return PGMR3SharedModuleGetPageState(PDMDevHlpGetVM(pDevIns), pReq->GCPtrPage, &pReq->fShared, &pReq->uPageFlags);
-#else
- return VERR_NOT_IMPLEMENTED;
-#endif
+ LogRelFlowFunc(("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);
+
+ LogRelFlowFunc(("new host capabilities: %#x\n", pThis->mouseCapabilities));
+
+ /*
+ * Notify connector if something changed.
+ */
+ if (fNotify)
+ {
+ LogRelFlowFunc(("notifying connector\n"));
+ pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
+ }
+
+ return VINF_SUCCESS;
}
-#endif /* VBOX_WITH_PAGE_SHARING */
+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;
+}
/**
- * Port I/O Handler for the generic request interface
- * @see FNIOMIOPORTOUT for details.
+ * Handles VMMDevReq_SetPointerShape.
*
- * @todo This function is too long!! All new request SHALL be implemented as
- * functions called from the switch! When making changes, please move the
- * relevant cases into functions.
+ * @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 DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
+static int vmmdevReqHandler_SetPointerShape(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
{
- VMMDevState *pThis = (VMMDevState*)pvUser;
- int rcRet = VINF_SUCCESS;
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ 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.size, pReq->header.version));
+ return VERR_INVALID_PARAMETER;
+ }
- /*
- * The caller has passed the guest context physical address
- * of the request structure. Copy the request packet.
- */
- VMMDevRequestHeader *pRequestHeader = NULL;
- VMMDevRequestHeader requestHeader;
- RT_ZERO(requestHeader);
+ bool fVisible = (pReq->fFlags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
+ bool fAlpha = (pReq->fFlags & VBOX_MOUSE_POINTER_ALPHA) != 0;
+ bool fShape = (pReq->fFlags & VBOX_MOUSE_POINTER_SHAPE) != 0;
- PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
+ Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
+ fVisible, fAlpha, fShape, pReq->width, pReq->height));
- /* the structure size must be greater or equal to the header size */
- if (requestHeader.size < sizeof(VMMDevRequestHeader))
+ if (pReq->header.size == sizeof(VMMDevReqMousePointer))
{
- Log(("VMMDev request header size too small! size = %d\n", requestHeader.size));
- rcRet = VINF_SUCCESS;
- goto l_end; /** @todo shouldn't (/ no need to) write back.*/
+ /* The guest did not provide the shape actually. */
+ fShape = false;
}
- /* check the version of the header structure */
- if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
+ /* forward call to driver */
+ if (fShape)
{
- Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
- rcRet = VINF_SUCCESS;
- goto l_end; /** @todo shouldn't (/ no need to) write back.*/
- }
-
- Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
+ int rc = vmmdevVerifyPointerShape(pReq);
+ if (RT_FAILURE(rc))
+ return rc;
- /* Newer additions starts with VMMDevReq_ReportGuestInfo2, older additions
- started with VMMDevReq_ReportGuestInfo. */
- if ( !pThis->fu32AdditionsOk
- && requestHeader.requestType != VMMDevReq_ReportGuestInfo2
- && requestHeader.requestType != VMMDevReq_ReportGuestInfo
- && requestHeader.requestType != VMMDevReq_WriteCoreDump
- && requestHeader.requestType != VMMDevReq_GetHostVersion) /* Always allow the guest to query the host capabilities. */
- {
- Log(("VMMDev: guest has not yet reported to us. Refusing operation of request #%d!\n",
- requestHeader.requestType));
- requestHeader.rc = VERR_NOT_SUPPORTED;
- static int cRelWarn;
- if (cRelWarn < 10)
- {
- cRelWarn++;
- LogRel(("VMMDev: the guest has not yet reported to us -- refusing operation of request #%d\n",
- requestHeader.requestType));
- }
- rcRet = VINF_SUCCESS;
- goto l_end;
+ pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
+ fVisible,
+ fAlpha,
+ pReq->xHot, pReq->yHot,
+ pReq->width, pReq->height,
+ pReq->pointerData);
}
-
- /* Check upper limit */
- if (requestHeader.size > VMMDEV_MAX_VMMDEVREQ_SIZE)
+ else
{
- static int cRelWarn;
- if (cRelWarn < 50)
- {
- cRelWarn++;
- LogRel(("VMMDev: request packet too big (%x). Refusing operation.\n", requestHeader.size));
- }
- requestHeader.rc = VERR_NOT_SUPPORTED;
- rcRet = VINF_SUCCESS;
- goto l_end;
+ pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
+ fVisible,
+ 0,
+ 0, 0,
+ 0, 0,
+ NULL);
}
- /* Read the entire request packet */
- pRequestHeader = (VMMDevRequestHeader *)RTMemAlloc(requestHeader.size);
- if (!pRequestHeader)
+ 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_UNLIKELY(pThis->fGetHostTimeDisabled))
+ return VERR_NOT_SUPPORTED;
+
+ RTTIMESPEC now;
+ pReq->time = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pThis->pDevIns, &now));
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * 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
{
- Log(("VMMDev: RTMemAlloc failed!\n"));
- rcRet = VINF_SUCCESS;
- requestHeader.rc = VERR_NO_MEMORY;
- goto l_end;
+ /* 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(("Guest reported fixed hypervisor window at 0%010x (size = %#x, rc = %Rrc)\n",
+ pReq->hypervisorStart, pReq->hypervisorSize, rc));
+ }
+ else if (RT_FAILURE(rc))
+ rc = VERR_TRY_AGAIN;
}
- PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, pRequestHeader, requestHeader.size);
+ return rc;
+}
- /* which request was sent? */
- switch (pRequestHeader->requestType)
- {
- /*
- * Guest wants to give up a timeslice
- */
- case VMMDevReq_Idle:
- {
- /* just return to EMT telling it that we want to halt */
- rcRet = VINF_EM_HALT;
- break;
- }
- /*
- * Guest is reporting its information
- */
- case VMMDevReq_ReportGuestInfo:
- {
- AssertMsgBreakStmt(pRequestHeader->size == sizeof(VMMDevReportGuestInfo), ("%u\n", pRequestHeader->size),
- pRequestHeader->rc = VERR_INVALID_PARAMETER);
- VBoxGuestInfo *pGuestInfo = &((VMMDevReportGuestInfo*)pRequestHeader)->guestInfo;
+/**
+ * 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);
- if (memcmp(&pThis->guestInfo, pGuestInfo, sizeof(*pGuestInfo)) != 0)
- {
- /* make a copy of supplied information */
- pThis->guestInfo = *pGuestInfo;
+ return VMMR3RegisterPatchMemory(PDMDevHlpGetVM(pThis->pDevIns), pReq->pPatchMem, pReq->cbPatchMem);
+}
- /* Check additions version */
- pThis->fu32AdditionsOk = VBOX_GUEST_INTERFACE_VERSION_OK(pThis->guestInfo.interfaceVersion);
- LogRel(("Guest Additions information report: Interface = 0x%08X osType = 0x%08X\n",
- pThis->guestInfo.interfaceVersion,
- pThis->guestInfo.osType));
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
- pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
- }
+/**
+ * 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);
- if (pThis->fu32AdditionsOk)
- {
- pRequestHeader->rc = VINF_SUCCESS;
- /* Clear our IRQ in case it was high for whatever reason. */
- PDMDevHlpPCISetIrqNoWait (pThis->pDevIns, 0, 0);
- }
- else
- pRequestHeader->rc = VERR_VERSION_MISMATCH;
- break;
+ 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(("Guest requests the VM to be suspended (paused)\n"));
+ return PDMDevHlpVMSuspend(pThis->pDevIns);
}
- case VMMDevReq_ReportGuestInfo2:
+ case VMMDevPowerState_PowerOff:
{
- pRequestHeader->rc = vmmdevReqHandler_ReportGuestInfo2(pThis, pRequestHeader);
- break;
+ LogRel(("Guest requests the VM to be turned off\n"));
+ return PDMDevHlpVMPowerOff(pThis->pDevIns);
}
- case VMMDevReq_WriteCoreDump:
+ case VMMDevPowerState_SaveState:
{
- if (pRequestHeader->size != sizeof(VMMDevReqWriteCoreDump))
+ if (true /*pThis->fAllowGuestToSaveState*/)
{
- AssertMsgFailed(("VMMDev WriteCoreDump structure has an invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
+ LogRel(("Guest requests the VM to be saved and powered off\n"));
+ return PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
}
- else
- {
- if (pThis->fGuestCoreDumpEnabled)
- {
- /*
- * User makes sure the directory exists.
- */
- 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.%d", szCorePath, i);
-
- char szFilePathNew[RTPATH_MAX];
- RTStrPrintf(szFilePathNew, sizeof(szFilePathNew), "%s.%d", szCorePath, i + 1);
- int vrc = RTFileMove(szFilePathOld, szFilePathNew, RTFILEMOVE_FLAGS_REPLACE);
- if (vrc == VERR_FILE_NOT_FOUND)
- RTFileDelete(szFilePathNew);
- }
-
- /*
- * Write the core file.
- */
- PVM pVM = PDMDevHlpGetVM(pDevIns);
- pRequestHeader->rc = DBGFR3CoreWrite(pVM, szCorePath, true /*fReplaceFile*/);
- }
- else
- pRequestHeader->rc = VERR_ACCESS_DENIED;
- }
- break;
+ LogRel(("Guest requests the VM to be saved and powered off, declined\n"));
+ return VERR_ACCESS_DENIED;
}
- case VMMDevReq_ReportGuestStatus:
- pRequestHeader->rc = vmmdevReqHandler_ReportGuestStatus(pThis, pRequestHeader);
- break;
+ default:
+ AssertMsgFailed(("VMMDev invalid power state request: %d\n", pReq->powerState));
+ return VERR_INVALID_PARAMETER;
+ }
+}
- /* Report guest capabilities */
- case VMMDevReq_ReportGuestCapabilities:
+
+/**
+ * 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
+ * @a VMMDevReq_GetDisplayChangeRequest (not the *2 version)
+ * will get into a @a 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 (pRequestHeader->size != sizeof(VMMDevReqGuestCapabilities))
- {
- AssertMsgFailed(("VMMDev guest caps structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
+ if (pThis->displayChangeData.aRequests[i].fPending)
{
- VMMDevReqGuestCapabilities *guestCaps = (VMMDevReqGuestCapabilities*)pRequestHeader;
-
- /* Enable this automatically for guests using the old
- request to report their capabilities. */
- /** @todo change this when we next bump the interface version */
- guestCaps->caps |= VMMDEV_GUEST_SUPPORTS_GRAPHICS;
- if (pThis->guestCaps != guestCaps->caps)
- {
- /* make a copy of supplied information */
- pThis->guestCaps = guestCaps->caps;
-
- LogRel(("Guest Additions capability report: (0x%x) "
- "seamless: %s, "
- "hostWindowMapping: %s, "
- "graphics: %s\n",
- guestCaps->caps,
- guestCaps->caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
- guestCaps->caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
- guestCaps->caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
-
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
- pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, guestCaps->caps);
- }
- pRequestHeader->rc = VINF_SUCCESS;
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
+ break;
}
- break;
}
- /* Change guest capabilities */
- case VMMDevReq_SetGuestCapabilities:
+ /* 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 (pRequestHeader->size != sizeof(VMMDevReqGuestCapabilities2))
- {
- AssertMsgFailed(("VMMDev guest caps structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
+ if (pThis->displayChangeData.aRequests[i].fPending)
{
- VMMDevReqGuestCapabilities2 *guestCaps = (VMMDevReqGuestCapabilities2*)pRequestHeader;
-
- pThis->guestCaps |= guestCaps->u32OrMask;
- pThis->guestCaps &= ~guestCaps->u32NotMask;
-
- LogRel(("Guest Additions capability report: (0x%x) "
- "seamless: %s, "
- "hostWindowMapping: %s, "
- "graphics: %s\n",
- pThis->guestCaps,
- pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
- pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
- pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
-
- if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
- pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
- pRequestHeader->rc = VINF_SUCCESS;
+ 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;
}
- break;
}
- /*
- * Retrieve mouse information
- */
- case VMMDevReq_GetMouseStatus:
+ /* Check if there are more pending requests. */
+ i++;
+ for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
{
- if (pRequestHeader->size != sizeof(VMMDevReqMouseStatus))
- {
- AssertMsgFailed(("VMMDev mouse status structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
+ if (pThis->displayChangeData.aRequests[i].fPending)
{
- VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)pRequestHeader;
- mouseStatus->mouseFeatures = pThis->mouseCapabilities
- & VMMDEV_MOUSE_MASK;
- mouseStatus->pointerXPos = pThis->mouseXAbs;
- mouseStatus->pointerYPos = pThis->mouseYAbs;
- LogRel2(("%s: VMMDevReq_GetMouseStatus: features = 0x%x, absX = %d, absY = %d\n",
- __PRETTY_FUNCTION__,
- mouseStatus->mouseFeatures,
- mouseStatus->pointerXPos,
- mouseStatus->pointerYPos));
- pRequestHeader->rc = VINF_SUCCESS;
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
+ Log3(("VMMDev: another pending at %u\n", i));
+ break;
}
- break;
}
- /*
- * Set mouse information
- */
- case VMMDevReq_SetMouseStatus:
+ if (pDispRequest)
{
- if (pRequestHeader->size != sizeof(VMMDevReqMouseStatus))
- {
- AssertMsgFailed(("VMMDev mouse status structure has invalid size %d (%#x) version=%d!\n",
- pRequestHeader->size, pRequestHeader->size, pRequestHeader->size, pRequestHeader->version));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- bool fNotify = false;
-
- uint32_t fFeatures =
- ((VMMDevReqMouseStatus*)pRequestHeader)->mouseFeatures;
-
- LogRelFlowFunc(("VMMDevReqMouseStatus: mouseFeatures = 0x%x\n",
- fFeatures));
-
- if ( (fFeatures & VMMDEV_MOUSE_NOTIFY_HOST_MASK)
- != ( pThis->mouseCapabilities
- & VMMDEV_MOUSE_NOTIFY_HOST_MASK))
- fNotify = true;
- pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
- pThis->mouseCapabilities |=
- (fFeatures & VMMDEV_MOUSE_GUEST_MASK);
- LogRelFlowFunc(("VMMDevReq_SetMouseStatus: new host capabilities: 0x%x\n",
- pThis->mouseCapabilities));
-
- /*
- * Notify connector if something has changed
- */
- if (fNotify)
- {
- LogRelFlowFunc(("VMMDevReq_SetMouseStatus: notifying connector\n"));
- pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
- }
- pRequestHeader->rc = VINF_SUCCESS;
- }
+ /* Current request has been read at least once. */
+ pDispRequest->fPending = false;
- break;
+ /* Remember which resolution the client has queried, subsequent reads
+ * will return the same values. */
+ pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
+ pThis->displayChangeData.fGuestSentChangeEventAck = true;
}
-
- /*
- * Set a new mouse pointer shape
- */
- case VMMDevReq_SetPointerShape:
+ else
{
- if (pRequestHeader->size < sizeof(VMMDevReqMousePointer))
- {
- AssertMsg(pRequestHeader->size == 0x10028 && pRequestHeader->version == 10000, /* don't complain about legacy!!! */
- ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
- pRequestHeader->size, pRequestHeader->size, pRequestHeader->size, pRequestHeader->version));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevReqMousePointer *pointerShape = (VMMDevReqMousePointer*)pRequestHeader;
+ Log3(("VMMDev: no pending request!!!\n"));
+ }
+ }
- bool fVisible = (pointerShape->fFlags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
- bool fAlpha = (pointerShape->fFlags & VBOX_MOUSE_POINTER_ALPHA) != 0;
- bool fShape = (pointerShape->fFlags & VBOX_MOUSE_POINTER_SHAPE) != 0;
+ if (!pDispRequest)
+ {
+ Log3(("VMMDev: default to %d\n", pThis->displayChangeData.iCurrentMonitor));
+ pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
+ }
- Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
- fVisible, fAlpha, fShape, pointerShape->width, pointerShape->height));
+ 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));
- if (pRequestHeader->size == sizeof(VMMDevReqMousePointer))
- {
- /* The guest did not provide the shape actually. */
- fShape = false;
- }
+ return VINF_SUCCESS;
+}
- /* forward call to driver */
- if (fShape)
- {
- pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
- fVisible,
- fAlpha,
- pointerShape->xHot, pointerShape->yHot,
- pointerShape->width, pointerShape->height,
- pointerShape->pointerData);
- }
- else
- {
- pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
- fVisible,
- 0,
- 0, 0,
- 0, 0,
- NULL);
- }
- pThis->fHostCursorRequested = fVisible;
- pRequestHeader->rc = VINF_SUCCESS;
- }
- break;
- }
- /*
- * Query the system time from the host
- */
- case VMMDevReq_GetHostTime:
- {
- if (pRequestHeader->size != sizeof(VMMDevReqHostTime))
- {
- AssertMsgFailed(("VMMDev host time structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (RT_UNLIKELY(pThis->fGetHostTimeDisabled))
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- else
- {
- VMMDevReqHostTime *hostTimeReq = (VMMDevReqHostTime*)pRequestHeader;
- RTTIMESPEC now;
- hostTimeReq->time = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &now));
- pRequestHeader->rc = VINF_SUCCESS;
- }
- break;
- }
+/**
+ * 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);
- /*
- * Query information about the hypervisor
- */
- case VMMDevReq_GetHypervisorInfo:
- {
- if (pRequestHeader->size != sizeof(VMMDevReqHypervisorInfo))
- {
- AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)pRequestHeader;
- PVM pVM = PDMDevHlpGetVM(pDevIns);
- pRequestHeader->rc = PGMR3MappingsSize(pVM, &hypervisorInfo->hypervisorSize);
- }
- break;
- }
+ DISPLAYCHANGEREQUEST *pDispRequest = NULL;
- /*
- * Set hypervisor information
- */
- case VMMDevReq_SetHypervisorInfo:
+ 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 (pRequestHeader->size != sizeof(VMMDevReqHypervisorInfo))
+ if (pThis->displayChangeData.aRequests[i].fPending)
{
- AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)pRequestHeader;
- PVM pVM = PDMDevHlpGetVM(pDevIns);
- if (hypervisorInfo->hypervisorStart == 0)
- pRequestHeader->rc = PGMR3MappingsUnfix(pVM);
- else
- {
- /* only if the client has queried the size before! */
- uint32_t mappingsSize;
- pRequestHeader->rc = PGMR3MappingsSize(pVM, &mappingsSize);
- if (RT_SUCCESS(pRequestHeader->rc) && hypervisorInfo->hypervisorSize == mappingsSize)
- {
- /* new reservation */
- pRequestHeader->rc = PGMR3MappingsFix(pVM, hypervisorInfo->hypervisorStart,
- hypervisorInfo->hypervisorSize);
- LogRel(("Guest reported fixed hypervisor window at 0x%p (size = 0x%x, rc = %Rrc)\n",
- (uintptr_t)hypervisorInfo->hypervisorStart,
- hypervisorInfo->hypervisorSize,
- pRequestHeader->rc));
- }
- }
+ 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;
}
- break;
}
- case VMMDevReq_RegisterPatchMemory:
+ /* Check if there are more pending requests. */
+ i++;
+ for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
{
- if (pRequestHeader->size != sizeof(VMMDevReqPatchMemory))
+ if (pThis->displayChangeData.aRequests[i].fPending)
{
- AssertMsgFailed(("VMMDevReq_RegisterPatchMemory structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevReqPatchMemory *pPatchRequest = (VMMDevReqPatchMemory*)pRequestHeader;
-
- pRequestHeader->rc = VMMR3RegisterPatchMemory(PDMDevHlpGetVM(pDevIns), pPatchRequest->pPatchMem, pPatchRequest->cbPatchMem);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
+ Log3(("VMMDev: another pending at %d\n",
+ i));
+ break;
}
- break;
}
- case VMMDevReq_DeregisterPatchMemory:
+ if (pDispRequest)
{
- if (pRequestHeader->size != sizeof(VMMDevReqPatchMemory))
- {
- AssertMsgFailed(("VMMDevReq_DeregisterPatchMemory structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevReqPatchMemory *pPatchRequest = (VMMDevReqPatchMemory*)pRequestHeader;
+ /* Current request has been read at least once. */
+ pDispRequest->fPending = false;
- pRequestHeader->rc = VMMR3DeregisterPatchMemory(PDMDevHlpGetVM(pDevIns), pPatchRequest->pPatchMem, pPatchRequest->cbPatchMem);
- }
- break;
+ /* Remember which resolution the client has queried, subsequent reads
+ * will return the same values. */
+ pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
+ pThis->displayChangeData.fGuestSentChangeEventAck = true;
}
-
- /*
- * Set the system power status
- */
- case VMMDevReq_SetPowerStatus:
+ else
{
- if (pRequestHeader->size != sizeof(VMMDevPowerStateRequest))
- {
- AssertMsgFailed(("VMMDev power state request structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevPowerStateRequest *powerStateRequest = (VMMDevPowerStateRequest*)pRequestHeader;
- switch(powerStateRequest->powerState)
- {
- case VMMDevPowerState_Pause:
- {
- LogRel(("Guest requests the VM to be suspended (paused)\n"));
- pRequestHeader->rc = rcRet = PDMDevHlpVMSuspend(pDevIns);
- break;
- }
-
- case VMMDevPowerState_PowerOff:
- {
- LogRel(("Guest requests the VM to be turned off\n"));
- pRequestHeader->rc = rcRet = PDMDevHlpVMPowerOff(pDevIns);
- break;
- }
-
- case VMMDevPowerState_SaveState:
- {
- if (true /*pThis->fAllowGuestToSaveState*/)
- {
- LogRel(("Guest requests the VM to be saved and powered off\n"));
- pRequestHeader->rc = rcRet = PDMDevHlpVMSuspendSaveAndPowerOff(pDevIns);
- }
- else
- {
- LogRel(("Guest requests the VM to be saved and powered off, declined\n"));
- pRequestHeader->rc = VERR_ACCESS_DENIED;
- }
- break;
- }
-
- default:
- AssertMsgFailed(("VMMDev invalid power state request: %d\n", powerStateRequest->powerState));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- break;
- }
- }
- break;
+ Log3(("VMMDev: no pending request!!!\n"));
}
+ }
- /*
- * Retrieve a display resize request sent by the host using
- * @a IDisplay:setVideoModeHint. Deprecated.
- * See documentation in VMMDev.h.
- */
- /**
- * @todo It looks like a multi-monitor guest which only uses
- * @a VMMDevReq_GetDisplayChangeRequest (not the *2 version)
- * will get into a @a 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?
- */
- case VMMDevReq_GetDisplayChangeRequest:
- {
- if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest))
- {
- /* Assert only if the size also not equal to a previous version size to prevent
- * assertion with old additions.
- */
- AssertMsg(pRequestHeader->size == sizeof(VMMDevDisplayChangeRequest) - sizeof (uint32_t),
- ("VMMDev display change request structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevDisplayChangeRequest *displayChangeRequest = (VMMDevDisplayChangeRequest*)pRequestHeader;
+ if (!pDispRequest)
+ {
+ Log3(("VMMDev: default to %d\n",
+ pThis->displayChangeData.iCurrentMonitor));
+ pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
+ }
- DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[0];
+ 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;
- if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
- {
- /* Current request has been read at least once. */
- pRequest->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. */
- pRequest->lastReadDisplayChangeRequest = pRequest->displayChangeRequest;
- pThis->displayChangeData.fGuestSentChangeEventAck = true;
- }
+ }
+ 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));
- if (pThis->displayChangeData.fGuestSentChangeEventAck)
- {
- displayChangeRequest->xres = pRequest->lastReadDisplayChangeRequest.xres;
- displayChangeRequest->yres = pRequest->lastReadDisplayChangeRequest.yres;
- displayChangeRequest->bpp = pRequest->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. */
- displayChangeRequest->xres = pRequest->displayChangeRequest.xres;
- displayChangeRequest->yres = pRequest->displayChangeRequest.yres;
- displayChangeRequest->bpp = pRequest->displayChangeRequest.bpp;
- }
- Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n",
- displayChangeRequest->xres, displayChangeRequest->yres, displayChangeRequest->bpp));
+ return VINF_SUCCESS;
+}
- pRequestHeader->rc = VINF_SUCCESS;
- }
- break;
- }
- /*
- * Retrieve a display resize request sent by the host using
- * @a IDisplay:setVideoModeHint.
- * See documentation in VMMDev.h.
- */
- case VMMDevReq_GetDisplayChangeRequest2:
- {
- if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest2))
- {
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevDisplayChangeRequest2 *displayChangeRequest = (VMMDevDisplayChangeRequest2*)pRequestHeader;
+/**
+ * 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);
+}
- DISPLAYCHANGEREQUEST *pRequest = NULL;
- if (displayChangeRequest->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)
- {
- pRequest = &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 (pRequest)
- {
- /* Current request has been read at least once. */
- pRequest->fPending = false;
-
- /* Remember which resolution the client has queried, subsequent reads
- * will return the same values. */
- pRequest->lastReadDisplayChangeRequest = pRequest->displayChangeRequest;
- pThis->displayChangeData.fGuestSentChangeEventAck = true;
- }
- else
- {
- Log3(("VMMDev: no pending request!!!\n"));
- }
- }
+/**
+ * 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);
+}
- if (!pRequest)
- {
- Log3(("VMMDev: default to %d\n",
- pThis->displayChangeData.iCurrentMonitor));
- pRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
- }
- if (pThis->displayChangeData.fGuestSentChangeEventAck)
- {
- displayChangeRequest->xres = pRequest->lastReadDisplayChangeRequest.xres;
- displayChangeRequest->yres = pRequest->lastReadDisplayChangeRequest.yres;
- displayChangeRequest->bpp = pRequest->lastReadDisplayChangeRequest.bpp;
- displayChangeRequest->display = pRequest->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. */
- displayChangeRequest->xres = pRequest->displayChangeRequest.xres;
- displayChangeRequest->yres = pRequest->displayChangeRequest.yres;
- displayChangeRequest->bpp = pRequest->displayChangeRequest.bpp;
- displayChangeRequest->display = pRequest->displayChangeRequest.display;
- }
- Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
- displayChangeRequest->xres, displayChangeRequest->yres, displayChangeRequest->bpp, displayChangeRequest->display));
- pRequestHeader->rc = VINF_SUCCESS;
- }
- break;
- }
+/**
+ * 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);
- /*
- * Query whether the given video mode is supported
- */
- case VMMDevReq_VideoModeSupported:
- {
- if (pRequestHeader->size != sizeof(VMMDevVideoModeSupportedRequest))
- {
- AssertMsgFailed(("VMMDev video mode supported request structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevVideoModeSupportedRequest *videoModeSupportedRequest = (VMMDevVideoModeSupportedRequest*)pRequestHeader;
- /* forward the call */
- pRequestHeader->rc = pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
- 0, /* primary screen. */
- videoModeSupportedRequest->width,
- videoModeSupportedRequest->height,
- videoModeSupportedRequest->bpp,
- &videoModeSupportedRequest->fSupported);
- }
- break;
- }
+ /* forward the call */
+ return pThis->pDrv->pfnGetHeightReduction(pThis->pDrv, &pReq->heightReduction);
+}
- /*
- * Query whether the given video mode is supported for a specific display
- */
- case VMMDevReq_VideoModeSupported2:
- {
- if (pRequestHeader->size != sizeof(VMMDevVideoModeSupportedRequest2))
- {
- AssertMsgFailed(("VMMDev video mode supported request 2 structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevVideoModeSupportedRequest2 *videoModeSupportedRequest2 = (VMMDevVideoModeSupportedRequest2*)pRequestHeader;
- /* forward the call */
- pRequestHeader->rc = pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
- videoModeSupportedRequest2->display,
- videoModeSupportedRequest2->width,
- videoModeSupportedRequest2->height,
- videoModeSupportedRequest2->bpp,
- &videoModeSupportedRequest2->fSupported);
- }
- break;
- }
- /*
- * Query the height reduction in pixels
- */
- case VMMDevReq_GetHeightReduction:
+/**
+ * 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 (VBOX_GUEST_INTERFACE_VERSION_1_03(pThis))
+ {
+ vmmdevSetIRQ_Legacy(pThis);
+ }
+ else
+ {
+ if (pThis->fNewGuestFilterMask)
{
- if (pRequestHeader->size != sizeof(VMMDevGetHeightReductionRequest))
- {
- AssertMsgFailed(("VMMDev height reduction request structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevGetHeightReductionRequest *heightReductionRequest = (VMMDevGetHeightReductionRequest*)pRequestHeader;
- /* forward the call */
- pRequestHeader->rc = pThis->pDrv->pfnGetHeightReduction(pThis->pDrv,
- &heightReductionRequest->heightReduction);
- }
- break;
+ pThis->fNewGuestFilterMask = false;
+ pThis->u32GuestFilterMask = pThis->u32NewGuestFilterMask;
}
- /*
- * Acknowledge VMMDev events
- */
- case VMMDevReq_AcknowledgeEvents:
- {
- if (pRequestHeader->size != sizeof(VMMDevEvents))
- {
- AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- if (VBOX_GUEST_INTERFACE_VERSION_1_03 (pThis))
- {
- vmmdevSetIRQ_Legacy_EMT (pThis);
- }
- else
- {
- VMMDevEvents *pAckRequest;
+ pReq->events = pThis->u32HostEventFlags & pThis->u32GuestFilterMask;
- if (pThis->fNewGuestFilterMask)
- {
- pThis->fNewGuestFilterMask = false;
- pThis->u32GuestFilterMask = pThis->u32NewGuestFilterMask;
- }
+ pThis->u32HostEventFlags &= ~pThis->u32GuestFilterMask;
+ pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = false;
+ PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
+ }
+ return VINF_SUCCESS;
+}
- pAckRequest = (VMMDevEvents *)pRequestHeader;
- pAckRequest->events =
- pThis->u32HostEventFlags & pThis->u32GuestFilterMask;
- pThis->u32HostEventFlags &= ~pThis->u32GuestFilterMask;
- pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = false;
- PDMDevHlpPCISetIrqNoWait (pThis->pDevIns, 0, 0);
- }
- pRequestHeader->rc = VINF_SUCCESS;
- }
- break;
- }
+/**
+ * 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);
- /*
- * Change guest filter mask
- */
- case VMMDevReq_CtlGuestFilterMask:
- {
- if (pRequestHeader->size != sizeof(VMMDevCtlGuestFilterMask))
- {
- AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevCtlGuestFilterMask *pCtlMaskRequest;
-
- pCtlMaskRequest = (VMMDevCtlGuestFilterMask *)pRequestHeader;
- LogRelFlowFunc(("VMMDevCtlGuestFilterMask: or mask: 0x%x, not mask: 0x%x\n",
- pCtlMaskRequest->u32OrMask,
- pCtlMaskRequest->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,
- pCtlMaskRequest->u32OrMask,
- pCtlMaskRequest->u32NotMask & ~VMMDEV_EVENT_HGCM);
- pRequestHeader->rc = VINF_SUCCESS;
+ LogRelFlowFunc(("VMMDevCtlGuestFilterMask: or mask: %#x, not mask: %#x\n", pReq->u32OrMask, pReq->u32NotMask));
- }
- break;
- }
+ /* 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
- /*
- * Process HGCM request
- */
- case VMMDevReq_HGCMConnect:
- {
- if (pRequestHeader->size < sizeof(VMMDevHGCMConnect))
- {
- AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pRequestHeader;
- Log(("VMMDevReq_HGCMConnect\n"));
+/**
+ * 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 >= ... */
- pRequestHeader->rc = vmmdevHGCMConnect (pThis, pHGCMConnect, (RTGCPHYS)u32);
- }
- break;
- }
+ if (!pThis->pHGCMDrv)
+ {
+ Log(("VMMDevReq_HGCMConnect: HGCM Connector is NULL!\n"));
+ return VERR_NOT_SUPPORTED;
+ }
- case VMMDevReq_HGCMDisconnect:
- {
- if (pRequestHeader->size < sizeof(VMMDevHGCMDisconnect))
- {
- AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)pRequestHeader;
+ Log(("VMMDevReq_HGCMConnect\n"));
+ return vmmdevHGCMConnect(pThis, pReq, GCPhysReqHdr);
+}
- Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
- pRequestHeader->rc = vmmdevHGCMDisconnect (pThis, pHGCMDisconnect, (RTGCPHYS)u32);
- }
- break;
- }
-#ifdef VBOX_WITH_64_BITS_GUESTS
- case VMMDevReq_HGCMCall32:
- case VMMDevReq_HGCMCall64:
-#else
- case VMMDevReq_HGCMCall:
-#endif /* VBOX_WITH_64_BITS_GUESTS */
- {
- if (pRequestHeader->size < sizeof(VMMDevHGCMCall))
- {
- AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pRequestHeader;
+/**
+ * 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 >= ... */
- Log2(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
- Log2(("%.*Rhxd\n", pRequestHeader->size, pRequestHeader));
+ if (!pThis->pHGCMDrv)
+ {
+ Log(("VMMDevReq_VMMDevHGCMDisconnect: HGCM Connector is NULL!\n"));
+ return VERR_NOT_SUPPORTED;
+ }
+
+ Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
+ return vmmdevHGCMDisconnect(pThis, pReq, GCPhysReqHdr);
+}
+
+
+/**
+ * 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)
+ {
+ Log(("VMMDevReq_HGCMCall: HGCM Connector is NULL!\n"));
+ return VERR_NOT_SUPPORTED;
+ }
+
+ 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 = (pRequestHeader->requestType == VMMDevReq_HGCMCall64);
+ bool f64Bits = (pReq->header.header.requestType == VMMDevReq_HGCMCall64);
#else
- bool f64Bits = false;
+ bool f64Bits = false;
#endif /* VBOX_WITH_64_BITS_GUESTS */
- pRequestHeader->rc = vmmdevHGCMCall (pThis, pHGCMCall, requestHeader.size, (RTGCPHYS)u32, f64Bits);
- }
- break;
- }
+ return vmmdevHGCMCall(pThis, pReq, pReq->header.header.size, GCPhysReqHdr, f64Bits);
+}
+
#endif /* VBOX_WITH_HGCM */
- case VMMDevReq_HGCMCancel:
- {
- if (pRequestHeader->size < sizeof(VMMDevHGCMCancel))
- {
- AssertMsgFailed(("VMMDevReq_HGCMCancel structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_HGCMCancel HGCM Connector is NULL!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- VMMDevHGCMCancel *pHGCMCancel = (VMMDevHGCMCancel *)pRequestHeader;
+/**
+ * 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 >= ... */
- Log(("VMMDevReq_VMMDevHGCMCancel\n"));
- pRequestHeader->rc = vmmdevHGCMCancel (pThis, pHGCMCancel, (RTGCPHYS)u32);
- }
- break;
- }
+ if (!pThis->pHGCMDrv)
+ {
+ Log(("VMMDevReq_VMMDevHGCMCancel: HGCM Connector is NULL!\n"));
+ return VERR_NOT_SUPPORTED;
+ }
- case VMMDevReq_HGCMCancel2:
- {
- if (pRequestHeader->size != sizeof(VMMDevHGCMCancel2))
- {
- AssertMsgFailed(("VMMDevReq_HGCMCancel structure has invalid size!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pHGCMDrv)
- {
- Log(("VMMDevReq_HGCMCancel HGCM Connector is NULL!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- VMMDevHGCMCancel2 *pHGCMCancel2 = (VMMDevHGCMCancel2 *)pRequestHeader;
+ Log(("VMMDevReq_VMMDevHGCMCancel\n"));
+ return vmmdevHGCMCancel(pThis, pReq, GCPhysReqHdr);
+}
- Log(("VMMDevReq_VMMDevHGCMCancel\n"));
- pRequestHeader->rc = vmmdevHGCMCancel2 (pThis, pHGCMCancel2->physReqToCancel);
- }
- break;
- }
- case VMMDevReq_VideoAccelEnable:
- {
- if (pRequestHeader->size < sizeof(VMMDevVideoAccelEnable))
- {
- Log(("VMMDevReq_VideoAccelEnable request size too small!!!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pDrv)
- {
- Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- VMMDevVideoAccelEnable *ptr = (VMMDevVideoAccelEnable *)pRequestHeader;
+/**
+ * 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 (ptr->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
- {
- /* The guest driver seems compiled with another headers. */
- Log(("VMMDevReq_VideoAccelEnable guest ring buffer size %d, should be %d!!!\n", ptr->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- /* The request is correct. */
- ptr->fu32Status |= VBVA_F_STATUS_ACCEPTED;
-
- LogFlow(("VMMDevReq_VideoAccelEnable ptr->u32Enable = %d\n", ptr->u32Enable));
-
- pRequestHeader->rc = ptr->u32Enable?
- pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, true, &pThis->pVMMDevRAMR3->vbvaMemory):
- pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, false, NULL);
-
- if ( ptr->u32Enable
- && RT_SUCCESS (pRequestHeader->rc))
- {
- ptr->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;
- }
- }
- }
- break;
- }
+ if (!pThis->pHGCMDrv)
+ {
+ Log(("VMMDevReq_HGCMConnect2: HGCM Connector is NULL!\n"));
+ return VERR_NOT_SUPPORTED;
+ }
- case VMMDevReq_VideoAccelFlush:
- {
- if (pRequestHeader->size < sizeof(VMMDevVideoAccelFlush))
- {
- AssertMsgFailed(("VMMDevReq_VideoAccelFlush request size too small.\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pDrv)
- {
- Log(("VMMDevReq_VideoAccelFlush Connector is NULL!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- pThis->pDrv->pfnVideoAccelFlush (pThis->pDrv);
+ Log(("VMMDevReq_VMMDevHGCMCancel\n"));
+ return vmmdevHGCMCancel2(pThis, pReq->physReqToCancel);
+}
- pRequestHeader->rc = VINF_SUCCESS;
- }
- break;
- }
- case VMMDevReq_VideoSetVisibleRegion:
- {
- if ( pRequestHeader->size + sizeof(RTRECT)
- < sizeof(VMMDevVideoSetVisibleRegion))
- {
- Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else if (!pThis->pDrv)
- {
- Log(("VMMDevReq_VideoSetVisibleRegion Connector is NULL!!!\n"));
- pRequestHeader->rc = VERR_NOT_SUPPORTED;
- }
- else
- {
- VMMDevVideoSetVisibleRegion *ptr = (VMMDevVideoSetVisibleRegion *)pRequestHeader;
+/**
+ * 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 ( ptr->cRect > _1M /* restrict to sane range */
- || pRequestHeader->size != sizeof(VMMDevVideoSetVisibleRegion) + ptr->cRect * sizeof(RTRECT) - sizeof(RTRECT))
- {
- Log(("VMMDevReq_VideoSetVisibleRegion: cRects=%#x doesn't match size=%#x or is out of bounds\n",
- ptr->cRect, pRequestHeader->size));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", ptr->cRect));
- /* forward the call */
- pRequestHeader->rc = pThis->pDrv->pfnSetVisibleRegion(pThis->pDrv, ptr->cRect, &ptr->Rect);
- }
- }
- break;
+ 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 another headers. */
+ Log(("VMMDevReq_VideoAccelEnable guest ring buffer size %d, should be %d!!!\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);
}
+ }
- case VMMDevReq_GetSeamlessChangeRequest:
+ /* 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 pThis The VMMDev instance data.
+ * @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(PVMMDEV pThis, 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 pThis The VMMDev instance data.
+ * @param pReqHdr The header of the request to handle.
+ */
+static int vmmdevReqHandler_LogString(PVMMDEV pThis, 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(LOG_INSTANCE, 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(memchr(pReq->szName, '\0', sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
+ AssertReturn(memchr(pReq->szVersion, '\0', sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
+
+ /*
+ * 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(memchr(pReq->szName, '\0', sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
+ AssertReturn(memchr(pReq->szVersion, '\0', sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
+
+ /*
+ * 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
+ 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--)
{
- if (pRequestHeader->size != sizeof(VMMDevSeamlessChangeRequest))
- {
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
+ char szFilePathOld[RTPATH_MAX];
+ if (i == 0)
+ RTStrCopy(szFilePathOld, sizeof(szFilePathOld), szCorePath);
else
- {
- VMMDevSeamlessChangeRequest *seamlessChangeRequest = (VMMDevSeamlessChangeRequest*)pRequestHeader;
- /* just pass on the information */
- Log(("VMMDev: returning seamless change request mode=%d\n", pThis->fSeamlessEnabled));
- if (pThis->fSeamlessEnabled)
- seamlessChangeRequest->mode = VMMDev_Seamless_Visible_Region;
- else
- seamlessChangeRequest->mode = VMMDev_Seamless_Disabled;
-
- if (seamlessChangeRequest->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
- {
- /* Remember which mode the client has queried. */
- pThis->fLastSeamlessEnabled = pThis->fSeamlessEnabled;
- }
+ RTStrPrintf(szFilePathOld, sizeof(szFilePathOld), "%s.%lld", szCorePath, i);
- pRequestHeader->rc = VINF_SUCCESS;
- }
- break;
+ 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);
}
- case VMMDevReq_GetVRDPChangeRequest:
- {
- if (pRequestHeader->size != sizeof(VMMDevVRDPChangeRequest))
- {
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevVRDPChangeRequest *vrdpChangeRequest = (VMMDevVRDPChangeRequest*)pRequestHeader;
- /* just pass on the information */
- Log(("VMMDev: returning VRDP status %d level %d\n", pThis->fVRDPEnabled, pThis->u32VRDPExperienceLevel));
+ /*
+ * Write the core file.
+ */
+ PUVM pUVM = PDMDevHlpGetUVM(pThis->pDevIns);
+ return DBGFR3CoreWrite(pUVM, szCorePath, true /*fReplaceFile*/);
+}
- vrdpChangeRequest->u8VRDPActive = pThis->fVRDPEnabled;
- vrdpChangeRequest->u32VRDPExperienceLevel = pThis->u32VRDPExperienceLevel;
- pRequestHeader->rc = VINF_SUCCESS;
- }
+/**
+ * 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_GetMemBalloonChangeRequest:
- {
- Log(("VMMDevReq_GetMemBalloonChangeRequest\n"));
- if (pRequestHeader->size != sizeof(VMMDevGetMemBalloonChangeRequest))
- {
- AssertFailed();
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevGetMemBalloonChangeRequest *memBalloonChangeRequest = (VMMDevGetMemBalloonChangeRequest*)pRequestHeader;
- /* just pass on the information */
- Log(("VMMDev: returning memory balloon size =%d\n", pThis->u32MemoryBalloonSize));
- memBalloonChangeRequest->cBalloonChunks = pThis->u32MemoryBalloonSize;
- memBalloonChangeRequest->cPhysMemChunks = pThis->cbGuestRAM / (uint64_t)_1M;
+ case VMMDevReq_ReportGuestInfo2:
+ pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo2(pThis, pReqHdr);
+ break;
- if (memBalloonChangeRequest->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
- {
- /* Remember which mode the client has queried. */
- pThis->u32LastMemoryBalloonSize = pThis->u32MemoryBalloonSize;
- }
+ case VMMDevReq_ReportGuestStatus:
+ pReqHdr->rc = vmmdevReqHandler_ReportGuestStatus(pThis, pReqHdr);
+ break;
- pRequestHeader->rc = VINF_SUCCESS;
- }
+ case VMMDevReq_ReportGuestUserState:
+ pReqHdr->rc = vmmdevReqHandler_ReportGuestUserState(pThis, pReqHdr);
break;
- }
- case VMMDevReq_ChangeMemBalloon:
- {
- VMMDevChangeMemBalloon *memBalloonChange = (VMMDevChangeMemBalloon*)pRequestHeader;
+ case VMMDevReq_ReportGuestCapabilities:
+ pReqHdr->rc = vmmdevReqHandler_ReportGuestCapabilities(pThis, pReqHdr);
+ break;
- Log(("VMMDevReq_ChangeMemBalloon\n"));
- if ( pRequestHeader->size < sizeof(VMMDevChangeMemBalloon)
- || memBalloonChange->cPages != VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
- || pRequestHeader->size != (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[memBalloonChange->cPages]))
- {
- AssertFailed();
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- pRequestHeader->rc = PGMR3PhysChangeMemBalloon(PDMDevHlpGetVM(pDevIns), !!memBalloonChange->fInflate, memBalloonChange->cPages, memBalloonChange->aPhysPage);
- if (memBalloonChange->fInflate)
- STAM_REL_U32_INC(&pThis->StatMemBalloonChunks);
- else
- STAM_REL_U32_DEC(&pThis->StatMemBalloonChunks);
- }
+ case VMMDevReq_SetGuestCapabilities:
+ pReqHdr->rc = vmmdevReqHandler_SetGuestCapabilities(pThis, pReqHdr);
break;
- }
- case VMMDevReq_GetStatisticsChangeRequest:
- {
- Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
- if (pRequestHeader->size != sizeof(VMMDevGetStatisticsChangeRequest))
- {
- AssertFailed();
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevGetStatisticsChangeRequest *statIntervalChangeRequest = (VMMDevGetStatisticsChangeRequest*)pRequestHeader;
- /* just pass on the information */
- Log(("VMMDev: returning statistics interval %d seconds\n", pThis->u32StatIntervalSize));
- statIntervalChangeRequest->u32StatInterval = pThis->u32StatIntervalSize;
+ case VMMDevReq_WriteCoreDump:
+ pReqHdr->rc = vmmdevReqHandler_WriteCoreDump(pThis, pReqHdr);
+ break;
- if (statIntervalChangeRequest->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
- {
- /* Remember which mode the client has queried. */
- pThis->u32LastStatIntervalSize= pThis->u32StatIntervalSize;
- }
+ case VMMDevReq_GetMouseStatus:
+ pReqHdr->rc = vmmdevReqHandler_GetMouseStatus(pThis, pReqHdr);
+ break;
- pRequestHeader->rc = VINF_SUCCESS;
- }
+ case VMMDevReq_SetMouseStatus:
+ pReqHdr->rc = vmmdevReqHandler_SetMouseStatus(pThis, pReqHdr);
break;
- }
- case VMMDevReq_ReportGuestStats:
- {
- Log(("VMMDevReq_ReportGuestStats\n"));
- if (pRequestHeader->size != sizeof(VMMDevReportGuestStats))
- {
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevReportGuestStats *stats = (VMMDevReportGuestStats*)pRequestHeader;
+ case VMMDevReq_SetPointerShape:
+ pReqHdr->rc = vmmdevReqHandler_SetPointerShape(pThis, pReqHdr);
+ break;
-#ifdef DEBUG
- VBoxGuestStatistics *pGuestStats = &stats->guestStats;
+ case VMMDevReq_GetHostTime:
+ pReqHdr->rc = vmmdevReqHandler_GetHostTime(pThis, pReqHdr);
+ break;
- Log(("Current statistics:\n"));
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
- Log(("CPU%d: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
+ case VMMDevReq_GetHypervisorInfo:
+ pReqHdr->rc = vmmdevReqHandler_GetHypervisorInfo(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
- Log(("CPU%d: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
+ case VMMDevReq_SetHypervisorInfo:
+ pReqHdr->rc = vmmdevReqHandler_SetHypervisorInfo(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
- Log(("CPU%d: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
+ case VMMDevReq_RegisterPatchMemory:
+ pReqHdr->rc = vmmdevReqHandler_RegisterPatchMemory(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
- Log(("CPU%d: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
+ case VMMDevReq_DeregisterPatchMemory:
+ pReqHdr->rc = vmmdevReqHandler_DeregisterPatchMemory(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
- Log(("CPU%d: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
+ case VMMDevReq_SetPowerStatus:
+ {
+ int rc = pReqHdr->rc = vmmdevReqHandler_SetPowerStatus(pThis, pReqHdr);
+ if (rc != VINF_SUCCESS && RT_SUCCESS(rc))
+ rcRet = rc;
+ break;
+ }
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
- Log(("CPU%d: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
+ case VMMDevReq_GetDisplayChangeRequest:
+ pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
- Log(("CPU%d: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
+ case VMMDevReq_GetDisplayChangeRequest2:
+ pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest2(pThis, pReqHdr);
+ break;
- /* Note that reported values are in pages; upper layers expect them in megabytes */
- Log(("CPU%d: Page size %-4d bytes\n", pGuestStats->u32CpuId, pGuestStats->u32PageSize));
- Assert(pGuestStats->u32PageSize == 4096);
+ case VMMDevReq_GetDisplayChangeRequestEx:
+ pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequestEx(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
- Log(("CPU%d: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/_4K)-1) / (_1M/_4K)));
+ case VMMDevReq_VideoModeSupported:
+ pReqHdr->rc = vmmdevReqHandler_VideoModeSupported(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
- Log(("CPU%d: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/_4K)));
+ case VMMDevReq_VideoModeSupported2:
+ pReqHdr->rc = vmmdevReqHandler_VideoModeSupported2(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
- Log(("CPU%d: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/_4K)));
+ case VMMDevReq_GetHeightReduction:
+ pReqHdr->rc = vmmdevReqHandler_GetHeightReduction(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
- Log(("CPU%d: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/_4K)));
+ case VMMDevReq_AcknowledgeEvents:
+ pReqHdr->rc = vmmdevReqHandler_AcknowledgeEvents(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
- Log(("CPU%d: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/_4K)));
+ case VMMDevReq_CtlGuestFilterMask:
+ pReqHdr->rc = vmmdevReqHandler_CtlGuestFilterMask(pThis, pReqHdr);
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
- Log(("CPU%d: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/_4K)));
+#ifdef VBOX_WITH_HGCM
+ case VMMDevReq_HGCMConnect:
+ pReqHdr->rc = vmmdevReqHandler_HGCMConnect(pThis, pReqHdr, GCPhysReqHdr);
+ *pfDelayedUnlock = true;
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
- Log(("CPU%d: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/_4K)));
+ case VMMDevReq_HGCMDisconnect:
+ pReqHdr->rc = vmmdevReqHandler_HGCMDisconnect(pThis, pReqHdr, GCPhysReqHdr);
+ *pfDelayedUnlock = true;
+ break;
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
- Log(("CPU%d: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/_4K)));
+# 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;
+#endif /* VBOX_WITH_HGCM */
- if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
- Log(("CPU%d: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/_4K)));
- Log(("Statistics end *******************\n"));
-#endif
+ case VMMDevReq_HGCMCancel:
+ pReqHdr->rc = vmmdevReqHandler_HGCMCancel(pThis, pReqHdr, GCPhysReqHdr);
+ *pfDelayedUnlock = true;
+ break;
- /* forward the call */
- pRequestHeader->rc = pThis->pDrv->pfnReportStatistics(pThis->pDrv, &stats->guestStats);
- }
+ case VMMDevReq_HGCMCancel2:
+ pReqHdr->rc = vmmdevReqHandler_HGCMCancel2(pThis, pReqHdr);
break;
- }
- case VMMDevReq_QueryCredentials:
- {
- if (pRequestHeader->size != sizeof(VMMDevCredentials))
- {
- AssertMsgFailed(("VMMDevReq_QueryCredentials request size too small.\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
+ case VMMDevReq_VideoAccelEnable:
+ pReqHdr->rc = vmmdevReqHandler_VideoAccelEnable(pThis, pReqHdr);
+ break;
- /* let's start by nulling out the data */
- memset(credentials->szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(credentials->szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
- memset(credentials->szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
+ case VMMDevReq_VideoAccelFlush:
+ pReqHdr->rc = vmmdevReqHandler_VideoAccelFlush(pThis, pReqHdr);
+ break;
- /* should we return whether we got credentials for a logon? */
- if (credentials->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
- {
- if ( pThis->pCredentials->Logon.szUserName[0]
- || pThis->pCredentials->Logon.szPassword[0]
- || pThis->pCredentials->Logon.szDomain[0])
- {
- credentials->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
- }
- else
- {
- credentials->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
- }
- }
+ case VMMDevReq_VideoSetVisibleRegion:
+ pReqHdr->rc = vmmdevReqHandler_VideoSetVisibleRegion(pThis, pReqHdr);
+ break;
- /* does the guest want to read logon credentials? */
- if (credentials->u32Flags & VMMDEV_CREDENTIALS_READ)
- {
- if (pThis->pCredentials->Logon.szUserName[0])
- strcpy(credentials->szUserName, pThis->pCredentials->Logon.szUserName);
- if (pThis->pCredentials->Logon.szPassword[0])
- strcpy(credentials->szPassword, pThis->pCredentials->Logon.szPassword);
- if (pThis->pCredentials->Logon.szDomain[0])
- strcpy(credentials->szDomain, pThis->pCredentials->Logon.szDomain);
- if (!pThis->pCredentials->Logon.fAllowInteractiveLogon)
- credentials->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
- else
- credentials->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
- }
+ case VMMDevReq_GetSeamlessChangeRequest:
+ pReqHdr->rc = vmmdevReqHandler_GetSeamlessChangeRequest(pThis, pReqHdr);
+ break;
- if (!pThis->fKeepCredentials)
- {
- /* does the caller want us to destroy the logon credentials? */
- if (credentials->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);
- }
- }
+ case VMMDevReq_GetVRDPChangeRequest:
+ pReqHdr->rc = vmmdevReqHandler_GetVRDPChangeRequest(pThis, pReqHdr);
+ break;
- /* does the guest want to read credentials for verification? */
- if (credentials->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
- {
- if (pThis->pCredentials->Judge.szUserName[0])
- strcpy(credentials->szUserName, pThis->pCredentials->Judge.szUserName);
- if (pThis->pCredentials->Judge.szPassword[0])
- strcpy(credentials->szPassword, pThis->pCredentials->Judge.szPassword);
- if (pThis->pCredentials->Judge.szDomain[0])
- strcpy(credentials->szDomain, pThis->pCredentials->Judge.szDomain);
- }
+ case VMMDevReq_GetMemBalloonChangeRequest:
+ pReqHdr->rc = vmmdevReqHandler_GetMemBalloonChangeRequest(pThis, pReqHdr);
+ break;
- /* does the caller want us to destroy the judgement credentials? */
- if (credentials->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);
- }
+ case VMMDevReq_ChangeMemBalloon:
+ pReqHdr->rc = vmmdevReqHandler_ChangeMemBalloon(pThis, pReqHdr);
+ break;
- pRequestHeader->rc = VINF_SUCCESS;
- }
+ case VMMDevReq_GetStatisticsChangeRequest:
+ pReqHdr->rc = vmmdevReqHandler_GetStatisticsChangeRequest(pThis, pReqHdr);
break;
- }
- case VMMDevReq_ReportCredentialsJudgement:
- {
- if (pRequestHeader->size != sizeof(VMMDevCredentials))
- {
- AssertMsgFailed(("VMMDevReq_ReportCredentialsJudgement request size too small.\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
+ case VMMDevReq_ReportGuestStats:
+ pReqHdr->rc = vmmdevReqHandler_ReportGuestStats(pThis, pReqHdr);
+ break;
- /* what does the guest think about the credentials? (note: the order is important here!) */
- if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
- {
- pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
- }
- else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
- {
- pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
- }
- else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
- {
- pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
- }
- else
- Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", credentials->u32Flags));
+ case VMMDevReq_QueryCredentials:
+ pReqHdr->rc = vmmdevReqHandler_QueryCredentials(pThis, pReqHdr);
+ break;
- pRequestHeader->rc = VINF_SUCCESS;
- }
+ case VMMDevReq_ReportCredentialsJudgement:
+ pReqHdr->rc = vmmdevReqHandler_ReportCredentialsJudgement(pThis, pReqHdr);
break;
- }
- /*
- * Implemented in 3.1.0.
- *
- * Note! The ring-0 VBoxGuestLib uses this to check whether
- * VMMDevHGCMParmType_PageList is supported.
- */
case VMMDevReq_GetHostVersion:
- {
- AssertMsgBreakStmt(pRequestHeader->size == sizeof(VMMDevReqHostVersion),
- ("%#x < %#x\n", pRequestHeader->size, sizeof(VMMDevReqLogString)),
- pRequestHeader->rc = VERR_INVALID_PARAMETER);
- VMMDevReqHostVersion *pReqHostVer = (VMMDevReqHostVersion*)pRequestHeader;
- pReqHostVer->major = RTBldCfgVersionMajor();
- pReqHostVer->minor = RTBldCfgVersionMinor();
- pReqHostVer->build = RTBldCfgVersionBuild();
- pReqHostVer->revision = RTBldCfgRevision();
- pReqHostVer->features = VMMDEV_HVF_HGCM_PHYS_PAGE_LIST;
- pReqHostVer->header.rc = VINF_SUCCESS;
+ pReqHdr->rc = vmmdevReqHandler_GetHostVersion(pThis, pReqHdr);
break;
- }
case VMMDevReq_GetCpuHotPlugRequest:
- {
- VMMDevGetCpuHotPlugRequest *pReqCpuHotPlug = (VMMDevGetCpuHotPlugRequest *)pRequestHeader;
-
- if (pRequestHeader->size != sizeof(VMMDevGetCpuHotPlugRequest))
- {
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- pReqCpuHotPlug->enmEventType = pThis->enmCpuHotPlugEvent;
- pReqCpuHotPlug->idCpuCore = pThis->idCpuCore;
- pReqCpuHotPlug->idCpuPackage = pThis->idCpuPackage;
- pReqCpuHotPlug->header.rc = VINF_SUCCESS;
-
- /* Clear the event */
- pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_None;
- pThis->idCpuCore = UINT32_MAX;
- pThis->idCpuPackage = UINT32_MAX;
- }
+ pReqHdr->rc = vmmdevReqHandler_GetCpuHotPlugRequest(pThis, pReqHdr);
break;
- }
case VMMDevReq_SetCpuHotPlugStatus:
- {
- VMMDevCpuHotPlugStatusRequest *pReqCpuHotPlugStatus = (VMMDevCpuHotPlugStatusRequest *)pRequestHeader;
-
- if (pRequestHeader->size != sizeof(VMMDevCpuHotPlugStatusRequest))
- {
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- pRequestHeader->rc = VINF_SUCCESS;
-
- if (pReqCpuHotPlugStatus->enmStatusType == VMMDevCpuStatusType_Disable)
- pThis->fCpuHotPlugEventsEnabled = false;
- else if (pReqCpuHotPlugStatus->enmStatusType == VMMDevCpuStatusType_Enable)
- pThis->fCpuHotPlugEventsEnabled = true;
- else
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
+ pReqHdr->rc = vmmdevReqHandler_SetCpuHotPlugStatus(pThis, pReqHdr);
break;
- }
#ifdef VBOX_WITH_PAGE_SHARING
case VMMDevReq_RegisterSharedModule:
- pRequestHeader->rc = vmmdevReqHandler_RegisterSharedModule(pDevIns,
- (VMMDevSharedModuleRegistrationRequest *)pRequestHeader);
+ pReqHdr->rc = vmmdevReqHandler_RegisterSharedModule(pThis, pReqHdr);
break;
case VMMDevReq_UnregisterSharedModule:
- pRequestHeader->rc = vmmdevReqHandler_UnregisterSharedModule(pDevIns,
- (VMMDevSharedModuleUnregistrationRequest *)pRequestHeader);
+ pReqHdr->rc = vmmdevReqHandler_UnregisterSharedModule(pThis, pReqHdr);
break;
case VMMDevReq_CheckSharedModules:
- pRequestHeader->rc = vmmdevReqHandler_CheckSharedModules(pDevIns,
- (VMMDevSharedModuleCheckRequest *)pRequestHeader);
+ pReqHdr->rc = vmmdevReqHandler_CheckSharedModules(pThis, pReqHdr);
break;
case VMMDevReq_GetPageSharingStatus:
- pRequestHeader->rc = vmmdevReqHandler_GetPageSharingStatus(pThis,
- (VMMDevPageSharingStatusRequest *)pRequestHeader);
+ pReqHdr->rc = vmmdevReqHandler_GetPageSharingStatus(pThis, pReqHdr);
break;
case VMMDevReq_DebugIsPageShared:
- pRequestHeader->rc = vmmdevReqHandler_DebugIsPageShared(pDevIns, (VMMDevPageIsSharedRequest *)pRequestHeader);
+ pReqHdr->rc = vmmdevReqHandler_DebugIsPageShared(pThis, pReqHdr);
break;
#endif /* VBOX_WITH_PAGE_SHARING */
#ifdef DEBUG
case VMMDevReq_LogString:
+ pReqHdr->rc = vmmdevReqHandler_LogString(pThis, 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:
{
- if (pRequestHeader->size < sizeof(VMMDevReqLogString))
- {
- AssertMsgFailed(("VMMDevReq_LogString request size too small.\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- VMMDevReqLogString *pReqLogString = (VMMDevReqLogString *)pRequestHeader;
- LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR,
- ("DEBUG LOG: %s", pReqLogString->szString));
- pRequestHeader->rc = VINF_SUCCESS;
- }
+ /* just return to EMT telling it that we want to halt */
+ rcRet = VINF_EM_HALT;
break;
}
-#endif
+ 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)
+{
+ 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)
+ {
/*
- * Get a unique session id for this VM; the id will be different after each start, reset or restore of the VM
- * This can be used for restore detection inside the guest.
+ * 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.
*/
- case VMMDevReq_GetSessionId:
+ if ( pThis->fu32AdditionsOk
+ || requestHeader.requestType == VMMDevReq_ReportGuestInfo2
+ || requestHeader.requestType == VMMDevReq_ReportGuestInfo
+ || requestHeader.requestType == VMMDevReq_WriteCoreDump
+ || requestHeader.requestType == VMMDevReq_GetHostVersion
+ )
{
- if (pRequestHeader->size != sizeof(VMMDevReqSessionId))
- {
- AssertMsgFailed(("VMMDevReq_GetSessionId request size too small.\n"));
- pRequestHeader->rc = VERR_INVALID_PARAMETER;
+ /*
+ * 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
{
- VMMDevReqSessionId *pReq = (VMMDevReqSessionId *)pRequestHeader;
- pReq->idSession = pThis->idSession;
- pRequestHeader->rc = VINF_SUCCESS;
+ Log(("VMMDev: RTMemAlloc failed!\n"));
+ requestHeader.rc = VERR_NO_MEMORY;
}
- break;
}
-
- default:
+ else
{
- pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
- Log(("VMMDev unknown request type %d\n", pRequestHeader->requestType));
- break;
+ static int s_cRelWarn;
+ if (s_cRelWarn < 10)
+ {
+ s_cRelWarn++;
+ LogRel(("VMMDev: the guest has not yet reported to us -- refusing operation of request #%d\n",
+ requestHeader.requestType));
+ }
+ requestHeader.rc = VERR_NOT_SUPPORTED;
}
}
+ else
+ {
+ static int s_cRelWarn;
+ if (s_cRelWarn < 50)
+ {
+ s_cRelWarn++;
+ LogRel(("VMMDev: request packet too big (%x). Refusing operation.\n", requestHeader.size));
+ }
+ requestHeader.rc = VERR_NOT_SUPPORTED;
+ }
-l_end:
- /* Write the result back to guest memory */
+ /*
+ * Write the result back to guest memory
+ */
if (pRequestHeader)
{
- PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, pRequestHeader, pRequestHeader->size);
+ PDMDevHlpPhysWrite(pDevIns, u32, pRequestHeader, pRequestHeader->size);
+ if (fDelayedUnlock)
+ PDMCritSectLeave(&pThis->CritSect);
RTMemFree(pRequestHeader);
}
else
{
/* early error case; write back header only */
- PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
+ PDMDevHlpPhysWrite(pDevIns, u32, &requestHeader, sizeof(requestHeader));
+ Assert(!fDelayedUnlock);
}
- PDMCritSectLeave(&pThis->CritSect);
return rcRet;
}
+
+/* -=-=-=-=-=- PCI Device -=-=-=-=-=- */
+
+
/**
- * Callback function for mapping an PCI I/O region.
- *
- * @return VBox status code.
- * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
- * @param iRegion The region number.
- * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
- * I/O port, else it's a physical address.
- * This address is *NOT* relative to pci_mem_base like earlier!
- * @param enmType One of the PCI_ADDRESS_SPACE_* values.
+ * @interface_method_impl{FNPCIIOREGIONMAP, MMIO/MMIO2 regions}
*/
-static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int)
+vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
{
LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
- VMMDevState *pThis = PCIDEV_2_VMMDEVSTATE(pPciDev);
+ PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
int rc;
if (iRegion == 1)
@@ -2441,47 +2722,140 @@ static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ i
/**
- * Callback function for mapping a PCI I/O region.
- *
- * @return VBox status code.
- * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
- * @param iRegion The region number.
- * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
- * I/O port, else it's a physical address.
- * This address is *NOT* relative to pci_mem_base like earlier!
- * @param enmType One of the PCI_ADDRESS_SPACE_* values.
+ * @interface_method_impl{FNPCIIOREGIONMAP, I/O Port Region}
*/
-static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int)
+vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
{
- VMMDevState *pThis = PCIDEV_2_VMMDEVSTATE(pPciDev);
- int rc = VINF_SUCCESS;
+ 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));
/*
- * Save the base port address to simplify Port offset calculations.
- */
- pThis->PortBase = (RTIOPORT)GCPhysAddress;
-
- /*
* Register our port IO handlers.
*/
- rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns,
- (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
- (void*)pThis, vmmdevRequestHandler,
- NULL, NULL, NULL, "VMMDev Request Handler");
+ int rc = PDMDevHlpIOPortRegister(pPciDev->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)
+{
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
+
+ if (!pThis->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
+ {
+
+ /* The raw version. */
+ switch (u32)
+ {
+ case '\r': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
+ case '\n': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
+ case '\t': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
+ default: LogIt(LOG_INSTANCE, 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(LOG_REL_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("Guest Log: %s\n", pThis->szMsg));
+ pThis->iMsg = 0;
+ }
+ else
+ {
+ if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
+ {
+ pThis->szMsg[pThis->iMsg] = '\0';
+ LogRelIt(LOG_REL_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("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)
+{
+ 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)
+{
+ 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)
{
- VMMDevState *pThis = RT_FROM_MEMBER(pInterface, VMMDevState, IBase);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThis->IPort);
@@ -2493,6 +2867,9 @@ static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const
return NULL;
}
+
+/* -=-=-=-=-=- ILeds -=-=-=-=-=- */
+
/**
* Gets the pointer to the status LED of a unit.
*
@@ -2503,7 +2880,7 @@ static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const
*/
static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
{
- VMMDevState *pThis = (VMMDevState *)( (uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, SharedFolders.ILeds) );
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, SharedFolders.ILeds);
if (iLUN == 0) /* LUN 0 is shared folders */
{
*ppLed = &pThis->SharedFolders.Led;
@@ -2512,154 +2889,161 @@ static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned
return VERR_PDM_LUN_NOT_FOUND;
}
-/* -=-=-=-=-=- IVMMDevPort -=-=-=-=-=- */
-
-/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
-#define IVMMDEVPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, IPort)) )
+/* -=-=-=-=-=- PDMIVMMDEVPORT (VMMDEV::IPort) -=-=-=-=-=- */
/**
- * Return the current absolute mouse position in pixels
- *
- * @returns VBox status code
- * @param pAbsX Pointer of result value, can be NULL
- * @param pAbsY Pointer of result value, can be NULL
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnQueryAbsoluteMouse}
*/
-static DECLCALLBACK(int) vmmdevQueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t *pAbsX, int32_t *pAbsY)
+static DECLCALLBACK(int) vmmdevIPort_QueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- if (pAbsX)
- *pAbsX = ASMAtomicReadS32(&pThis->mouseXAbs); /* why the atomic read? */
- if (pAbsY)
- *pAbsY = ASMAtomicReadS32(&pThis->mouseYAbs);
+ 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;
}
/**
- * Set the new absolute mouse position in pixels
- *
- * @returns VBox status code
- * @param absX New absolute X position
- * @param absY New absolute Y position
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnSetAbsoluteMouse}
*/
-static DECLCALLBACK(int) vmmdevSetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t absX, int32_t absY)
+static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- if (pThis->mouseXAbs == absX && pThis->mouseYAbs == absY)
+ if ( pThis->mouseXAbs != xAbs
+ || pThis->mouseYAbs != yAbs)
{
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
+ 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);
}
- Log2(("vmmdevSetAbsoluteMouse: settings absolute position to x = %d, y = %d\n", absX, absY));
- pThis->mouseXAbs = absX;
- pThis->mouseYAbs = absY;
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
+
PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
/**
- * Return the current mouse capability flags
- *
- * @returns VBox status code
- * @param pCapabilities Pointer of result value
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnQueryMouseCapabilities}
*/
-static DECLCALLBACK(int) vmmdevQueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pfCaps)
+static DECLCALLBACK(int) vmmdevIPort_QueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- if (!pfCaps)
- return VERR_INVALID_PARAMETER;
- *pfCaps = pThis->mouseCapabilities;
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
+ AssertPtrReturn(pfCapabilities, VERR_INVALID_PARAMETER);
+
+ *pfCapabilities = pThis->mouseCapabilities;
return VINF_SUCCESS;
}
/**
- * Set the current mouse capability flag (host side)
- *
- * @returns VBox status code
- * @param capabilities Capability mask
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnUpdateMouseCapabilities}
*/
-static DECLCALLBACK(int) vmmdevUpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)
+static DECLCALLBACK(int)
+vmmdevIPort_UpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ 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;
+ pThis->mouseCapabilities |= (fCapsAdded & VMMDEV_MOUSE_HOST_MASK)
+ | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
bool fNotify = fOldCaps != pThis->mouseCapabilities;
- LogRelFlowFunc(("fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify %s\n",
- fCapsAdded, fCapsRemoved, fNotify ? "TRUE" : "FALSE"));
+ LogRelFlowFunc(("fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify=%RTbool\n", fCapsAdded, fCapsRemoved, fNotify));
if (fNotify)
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
-
-static DECLCALLBACK(int) vmmdevRequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t xres, uint32_t yres, uint32_t bpp, uint32_t display)
+/**
+ * @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)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
- if (display >= RT_ELEMENTS(pThis->displayChangeData.aRequests))
- {
+ if (idxDisplay >= RT_ELEMENTS(pThis->displayChangeData.aRequests))
return VERR_INVALID_PARAMETER;
- }
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[display];
+ DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[idxDisplay];
/* Verify that the new resolution is different and that guest does not yet know about it. */
- bool fSameResolution = (!xres || (pRequest->lastReadDisplayChangeRequest.xres == xres)) &&
- (!yres || (pRequest->lastReadDisplayChangeRequest.yres == yres)) &&
- (!bpp || (pRequest->lastReadDisplayChangeRequest.bpp == bpp)) &&
- pRequest->lastReadDisplayChangeRequest.display == display;
-
- if (!xres && !yres && !bpp)
+ 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(("vmmdevRequestDisplayChange: same=%d. new: xres=%d, yres=%d, bpp=%d, display=%d. old: xres=%d, yres=%d, bpp=%d, display=%d.\n",
- fSameResolution, xres, yres, bpp, display, pRequest->lastReadDisplayChangeRequest.xres, pRequest->lastReadDisplayChangeRequest.yres, pRequest->lastReadDisplayChangeRequest.bpp, pRequest->lastReadDisplayChangeRequest.display));
+ 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));
if (!fSameResolution)
{
- LogRel(("VMMDev::SetVideoModeHint: got a video mode hint (%dx%dx%d) at %d\n",
- xres, yres, bpp, display));
+ 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));
/* we could validate the information here but hey, the guest can do that as well! */
- pRequest->displayChangeRequest.xres = xres;
- pRequest->displayChangeRequest.yres = yres;
- pRequest->displayChangeRequest.bpp = bpp;
- pRequest->displayChangeRequest.display = display;
+ 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 = true;
/* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
}
PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
-static DECLCALLBACK(int) vmmdevRequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
+/**
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnRequestSeamlessChange}
+ */
+static DECLCALLBACK(int) vmmdevIPort_RequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ 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(("vmmdevRequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
+ Log(("vmmdevIPort_RequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
if (!fSameMode)
{
@@ -2667,159 +3051,158 @@ static DECLCALLBACK(int) vmmdevRequestSeamlessChange(PPDMIVMMDEVPORT pInterface,
pThis->fSeamlessEnabled = fEnabled;
/* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
}
PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
-static DECLCALLBACK(int) vmmdevSetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t ulBalloonSize)
+/**
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnSetMemoryBalloon}
+ */
+static DECLCALLBACK(int) vmmdevIPort_SetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ 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->u32LastMemoryBalloonSize == ulBalloonSize);
-
- Log(("vmmdevSetMemoryBalloon: old=%d. new=%d\n", pThis->u32LastMemoryBalloonSize, ulBalloonSize));
-
- if (!fSame)
+ 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->u32MemoryBalloonSize = ulBalloonSize;
+ pThis->cMbMemoryBalloon = cMbBalloon;
/* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
}
PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
-static DECLCALLBACK(int) vmmdevVRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t u32VRDPExperienceLevel)
+/**
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnVRDPChange}
+ */
+static DECLCALLBACK(int) vmmdevIPort_VRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
- Log(("vmmdevVRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
+ Log(("vmmdevIPort_VRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
if (!fSame)
{
pThis->fVRDPEnabled = fVRDPEnabled;
- pThis->u32VRDPExperienceLevel = u32VRDPExperienceLevel;
+ pThis->uVRDPExperienceLevel = uVRDPExperienceLevel;
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_VRDP);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_VRDP);
}
PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
-static DECLCALLBACK(int) vmmdevSetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t ulStatInterval)
+/**
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnSetStatisticsInterval}
+ */
+static DECLCALLBACK(int) vmmdevIPort_SetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ 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 == ulStatInterval);
+ bool fSame = (pThis->u32LastStatIntervalSize == cSecsStatInterval);
- Log(("vmmdevSetStatisticsInterval: old=%d. new=%d\n", pThis->u32LastStatIntervalSize, ulStatInterval));
+ 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 = ulStatInterval;
+ pThis->u32StatIntervalSize = cSecsStatInterval;
/* IRQ so the guest knows what's going on */
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
}
PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
-
-static DECLCALLBACK(int) vmmdevSetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
- const char *pszPassword, const char *pszDomain,
- uint32_t u32Flags)
+/**
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnSetCredentials}
+ */
+static DECLCALLBACK(int) vmmdevIPort_SetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
+ const char *pszPassword, const char *pszDomain, uint32_t fFlags)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
- int rc = VINF_SUCCESS;
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
+ AssertReturn(fFlags & (VMMDEV_SETCREDENTIALS_GUESTLOGON | VMMDEV_SETCREDENTIALS_JUDGE), VERR_INVALID_PARAMETER);
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
- /* logon mode? */
- if (u32Flags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
+ /*
+ * 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 = !(u32Flags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
+ pThis->pCredentials->Logon.fAllowInteractiveLogon = !(fFlags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
}
- /* credentials verification mode? */
- else if (u32Flags & VMMDEV_SETCREDENTIALS_JUDGE)
+ /*
+ * 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);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_JUDGE_CREDENTIALS);
}
- else
- rc = VERR_INVALID_PARAMETER;
PDMCritSectLeave(&pThis->CritSect);
- return rc;
+ return VINF_SUCCESS;
}
/**
- * Notification from the Display. Especially useful when
- * acceleration is disabled after a video mode change.
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnVBVAChange}
*
- * @param fEnable Current acceleration status.
+ * Notification from the Display. Especially useful when acceleration is
+ * disabled after a video mode change.
*/
-static DECLCALLBACK(void) vmmdevVBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
+static DECLCALLBACK(void) vmmdevIPort_VBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
{
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
+ Log(("vmmdevIPort_VBVAChange: fEnabled = %d\n", fEnabled));
- Log(("vmmdevVBVAChange: fEnabled = %d\n", fEnabled));
-
- if (pThis)
- {
- pThis->u32VideoAccelEnabled = fEnabled;
- }
- return;
+ /* Only used by saved state, which I guess is why we don't bother with locking here. */
+ pThis->u32VideoAccelEnabled = fEnabled;
}
/**
- * Notification that a CPU is about to be unplugged from the VM.
- * The guest has to eject the CPU.
- *
- * @returns VBox status code.
- * @param idCpu The id of the CPU.
- * @param idCpuCore The core id of the CPU to remove.
- * @param idCpuPackage The package id of the CPU to remove.
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnCpuHotUnplug}
*/
-static DECLCALLBACK(int) vmmdevCpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
+static DECLCALLBACK(int) vmmdevIPort_CpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
{
- int rc = VINF_SUCCESS;
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
+ int rc = VINF_SUCCESS;
- Log(("vmmdevCpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
+ Log(("vmmdevIPort_CpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
- PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
if (pThis->fCpuHotPlugEventsEnabled)
{
pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
pThis->idCpuCore = idCpuCore;
pThis->idCpuPackage = idCpuPackage;
- VMMDevNotifyGuest (pThis, VMMDEV_EVENT_CPU_HOTPLUG);
+ VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
}
else
rc = VERR_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
@@ -2829,21 +3212,16 @@ static DECLCALLBACK(int) vmmdevCpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t
}
/**
- * Notification that a CPU was attached to the VM
- * The guest may use it now.
- *
- * @returns VBox status code.
- * @param idCpuCore The core id of the CPU to add.
- * @param idCpuPackage The package id of the CPU to add.
+ * @interface_method_impl{PDMIVMMDEVPORT, pfnCpuHotPlug}
*/
-static DECLCALLBACK(int) vmmdevCpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
+static DECLCALLBACK(int) vmmdevIPort_CpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
{
- int rc = VINF_SUCCESS;
- VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
+ 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_SEM_BUSY);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
if (pThis->fCpuHotPlugEventsEnabled)
{
@@ -2859,14 +3237,15 @@ static DECLCALLBACK(int) vmmdevCpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t i
return rc;
}
+
/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
/**
- * @copydoc FNSSMDEVLIVEEXEC
+ * @callback_method_impl{NSSMDEVLIVEEXEC}
*/
static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
{
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
SSMR3PutBool(pSSM, pThis->fGetHostTimeDisabled);
SSMR3PutBool(pSSM, pThis->fBackdoorLogDisabled);
@@ -2878,12 +3257,12 @@ static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uin
/**
- * @copydoc FNSSMDEVSAVEEXEC
- *
+ * @callback_method_impl{FNSSMDEVSAVEEXEC}
*/
static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
{
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
@@ -2925,18 +3304,19 @@ static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
SSMR3PutS64(pSSM, RTTimeSpecGetNano(&pThis->aFacilityStatuses[i].TimeSpecTS));
}
+ PDMCritSectLeave(&pThis->CritSect);
return VINF_SUCCESS;
}
/**
- * @copydoc FNSSMDEVLOADEXEC
+ * @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. */
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
- int rc;
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
+ int rc;
if ( uVersion > VMMDEV_SAVED_STATE_VERSION
|| uVersion < 6)
@@ -3073,8 +3453,7 @@ static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uin
if (pThis->fu32AdditionsOk)
{
LogRel(("Guest Additions information report: additionsVersion = 0x%08X, osType = 0x%08X\n",
- pThis->guestInfo.interfaceVersion,
- pThis->guestInfo.osType));
+ pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
if (pThis->pDrv)
{
if (pThis->guestInfo2.uFullVersion && pThis->pDrv->pfnUpdateGuestInfo2)
@@ -3111,7 +3490,7 @@ static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uin
*/
static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
{
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
#ifdef VBOX_WITH_HGCM
int rc = vmmdevHGCMLoadStateDone(pThis, pSSM);
@@ -3123,6 +3502,7 @@ static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM
return VINF_SUCCESS;
}
+
/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
/**
@@ -3130,22 +3510,21 @@ static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM
*
* @param pThis Pointer to the VMMDev instance data.
*/
-static void vmmdevInitRam(VMMDevState *pThis)
+static void vmmdevInitRam(PVMMDEV pThis)
{
memset(pThis->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
pThis->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
pThis->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
}
+
/**
- * Reset notification.
- *
- * @returns VBox status.
- * @param pDrvIns The driver instance data.
+ * @interface_method_impl{PDMDEVREG,pfnReset}
*/
static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
{
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
+ PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
/*
* Reset the mouse integration feature bits
@@ -3211,7 +3590,7 @@ static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
pThis->fLastSeamlessEnabled = false;
/* disabled memory ballooning */
- pThis->u32LastMemoryBalloonSize = 0;
+ pThis->cMbMemoryBalloonLast = 0;
/* disabled statistics updating */
pThis->u32LastStatIntervalSize = 0;
@@ -3251,6 +3630,8 @@ static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
* This can be used for restore detection inside the guest.
*/
pThis->idSession = ASMReadTSC();
+
+ PDMCritSectLeave(&pThis->CritSect);
}
@@ -3267,10 +3648,10 @@ static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta
/**
* @interface_method_impl{PDMDEVREG,pfnDestruct}
*/
-static DECLCALLBACK(int) vmmdevDestroy(PPDMDEVINS pDevIns)
+static DECLCALLBACK(int) vmmdevDestruct(PPDMDEVINS pDevIns)
{
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
/*
* Wipe and free the credentials.
@@ -3282,6 +3663,13 @@ static DECLCALLBACK(int) vmmdevDestroy(PPDMDEVINS pDevIns)
pThis->pCredentials = NULL;
}
+#ifndef VBOX_WITHOUT_TESTING_FEATURES
+ /*
+ * Clean up the testing device.
+ */
+ vmmdevTestingTerminate(pDevIns);
+#endif
+
return VINF_SUCCESS;
}
@@ -3291,8 +3679,8 @@ static DECLCALLBACK(int) vmmdevDestroy(PPDMDEVINS pDevIns)
*/
static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
+ PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
int rc;
- VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
Assert(iInstance == 0);
PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
@@ -3304,17 +3692,17 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
pThis->pDevIns = pDevIns;
/* PCI vendor, just a free bogus value */
- PCIDevSetVendorId(&pThis->dev, 0x80ee);
+ PCIDevSetVendorId(&pThis->PciDev, 0x80ee);
/* device ID */
- PCIDevSetDeviceId(&pThis->dev, 0xcafe);
+ PCIDevSetDeviceId(&pThis->PciDev, 0xcafe);
/* class sub code (other type of system peripheral) */
- PCIDevSetClassSub(&pThis->dev, 0x80);
+ PCIDevSetClassSub(&pThis->PciDev, 0x80);
/* class base code (base system peripheral) */
- PCIDevSetClassBase(&pThis->dev, 0x08);
+ PCIDevSetClassBase(&pThis->PciDev, 0x08);
/* header type */
- PCIDevSetHeaderType(&pThis->dev, 0x00);
+ PCIDevSetHeaderType(&pThis->PciDev, 0x00);
/* interrupt on pin 0 */
- PCIDevSetInterruptPin(&pThis->dev, 0x01);
+ PCIDevSetInterruptPin(&pThis->PciDev, 0x01);
RTTIMESPEC TimeStampNow;
RTTimeNow(&TimeStampNow);
@@ -3332,19 +3720,19 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
pThis->IBase.pfnQueryInterface = vmmdevPortQueryInterface;
/* VMMDev port */
- pThis->IPort.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
- pThis->IPort.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
- pThis->IPort.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
- pThis->IPort.pfnUpdateMouseCapabilities = vmmdevUpdateMouseCapabilities;
- pThis->IPort.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
- pThis->IPort.pfnSetCredentials = vmmdevSetCredentials;
- pThis->IPort.pfnVBVAChange = vmmdevVBVAChange;
- pThis->IPort.pfnRequestSeamlessChange = vmmdevRequestSeamlessChange;
- pThis->IPort.pfnSetMemoryBalloon = vmmdevSetMemoryBalloon;
- pThis->IPort.pfnSetStatisticsInterval = vmmdevSetStatisticsInterval;
- pThis->IPort.pfnVRDPChange = vmmdevVRDPChange;
- pThis->IPort.pfnCpuHotUnplug = vmmdevCpuHotUnplug;
- pThis->IPort.pfnCpuHotPlug = vmmdevCpuHotPlug;
+ 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;
@@ -3373,7 +3761,9 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
"GuestCoreDumpEnabled|"
"GuestCoreDumpDir|"
"GuestCoreDumpCount|"
- "TestingEnabled"
+ "TestingEnabled|"
+ "TestingMMIO|"
+ "TestintXmlOutputFile"
,
"");
@@ -3431,27 +3821,44 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
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
/*
- * Create the critical section for the device.
+ * 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 = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev#u", iInstance);
+ rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
+ AssertRCReturn(rc, rc);
+ rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev#%u", iInstance);
AssertRCReturn(rc, rc);
- /* Later: pDevIns->pCritSectR3 = &pThis->CritSect; */
/*
* Register the backdoor logging port
*/
- rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
+ rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog,
+ NULL, NULL, NULL, "VMMDev backdoor logging");
AssertRCReturn(rc, rc);
-#ifdef TIMESYNC_BACKDOOR
+#ifdef VMMDEV_WITH_ALT_TIMESYNC
/*
- * Alternative timesync source (temporary!)
+ * 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, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
+ rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL,
+ vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead,
+ NULL, NULL, "VMMDev timesync backdoor");
AssertRCReturn(rc, rc);
#endif
@@ -3475,11 +3882,11 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
/*
* Register the PCI device.
*/
- rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
+ rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
if (RT_FAILURE(rc))
return rc;
- if (pThis->dev.devfn != 32 || iInstance != 0)
- Log(("!!WARNING!!: pThis->dev.devfn=%d (ignore if testcase or no started by Main)\n", pThis->dev.devfn));
+ if (pThis->PciDev.devfn != 32 || iInstance != 0)
+ Log(("!!WARNING!!: pThis->PciDev.devfn=%d (ignore if testcase or no started by Main)\n", pThis->PciDev.devfn));
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
if (RT_FAILURE(rc))
return rc;
@@ -3520,10 +3927,10 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
#endif
/* Query the initial balloon size. */
AssertPtr(pThis->pDrv->pfnQueryBalloonSize);
- rc = pThis->pDrv->pfnQueryBalloonSize(pThis->pDrv, &pThis->u32MemoryBalloonSize);
+ rc = pThis->pDrv->pfnQueryBalloonSize(pThis->pDrv, &pThis->cMbMemoryBalloon);
AssertRC(rc);
- Log(("Initial balloon size %x\n", pThis->u32MemoryBalloonSize));
+ Log(("Initial balloon size %x\n", pThis->cMbMemoryBalloon));
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
@@ -3562,14 +3969,18 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
pThis->u32HGCMEnabled = 0;
#endif /* VBOX_WITH_HGCM */
- /* In this version of VirtualBox the GUI checks whether "needs host cursor"
- * changes. */
+ /*
+ * 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.
+ /*
+ * 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;
@@ -3601,10 +4012,10 @@ extern "C" const PDMDEVREG g_DeviceVMMDev =
/* pfnConstruct */
vmmdevConstruct,
/* pfnDestruct */
- NULL,
+ vmmdevDestruct,
/* pfnRelocate */
vmmdevRelocate,
- /* pfnIOCtl */
+ /* pfnMemSetup */
NULL,
/* pfnPowerOn */
NULL,
@@ -3630,3 +4041,4 @@ extern "C" const PDMDEVREG g_DeviceVMMDev =
PDM_DEVREG_VERSION
};
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
+
diff --git a/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp b/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp
index 4a531a89..ca942b1e 100644
--- a/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp
+++ b/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -16,6 +16,9 @@
*/
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_VMM
#include <iprt/alloc.h>
#include <iprt/asm.h>
@@ -39,7 +42,11 @@
# define VBOXDD_HGCMCALL_COMPLETED_DONE(a,b,c,d) do { } while (0)
#endif
-typedef enum _VBOXHGCMCMDTYPE
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+typedef enum VBOXHGCMCMDTYPE
{
VBOXHGCMCMDTYPE_LOADSTATE = 0,
VBOXHGCMCMDTYPE_CONNECT,
@@ -48,21 +55,23 @@ typedef enum _VBOXHGCMCMDTYPE
VBOXHGCMCMDTYPE_SizeHack = 0x7fffffff
} VBOXHGCMCMDTYPE;
-/* Information about a linear ptr parameter. */
-typedef struct _VBOXHGCMLINPTR
+/**
+ * Information about a linear ptr parameter.
+ */
+typedef struct VBOXHGCMLINPTR
{
- /* Index of the parameter. */
+ /** Index of the parameter. */
uint32_t iParm;
- /* Offset in the first physical page of the region. */
+ /** Offset in the first physical page of the region. */
uint32_t offFirstPage;
- /* How many pages. */
+ /** How many pages. */
uint32_t cPages;
- /* Pointer to array of the GC physical addresses for these pages.
- * It is assumed that the physical address of the locked resident
- * guest page does not change.
+ /** Pointer to array of the GC physical addresses for these pages.
+ * It is assumed that the physical address of the locked resident guest page
+ * does not change.
*/
RTGCPHYS *paPages;
@@ -70,78 +79,83 @@ typedef struct _VBOXHGCMLINPTR
struct VBOXHGCMCMD
{
- /* Active commands, list is protected by critsectHGCMCmdList. */
+ /** Active commands, list is protected by critsectHGCMCmdList. */
struct VBOXHGCMCMD *pNext;
struct VBOXHGCMCMD *pPrev;
- /* The type of the command. */
+ /** The type of the command. */
VBOXHGCMCMDTYPE enmCmdType;
- /* Whether the command was cancelled by the guest. */
+ /** Whether the command was cancelled by the guest. */
bool fCancelled;
- /* Whether the command is in the active commands list. */
+ /** Whether the command is in the active commands list. */
bool fInList;
- /* Whether the command was saved. */
+ /** Whether the command was saved. */
bool fSaved;
- /* GC physical address of the guest request. */
+ /** GC physical address of the guest request. */
RTGCPHYS GCPhys;
- /* Request packet size */
+ /** Request packet size */
uint32_t cbSize;
- /* Pointer to converted host parameters in case of a Call request.
+ /** Pointer to converted host parameters in case of a Call request.
* Parameters follow this structure in the same memory block.
*/
VBOXHGCMSVCPARM *paHostParms;
- /* Linear pointer parameters information. */
+ /* Number of elements in paHostParms */
+ uint32_t cHostParms;
+
+ /** Linear pointer parameters information. */
int cLinPtrs;
- /* How many pages for all linptrs of this command.
+ /** How many pages for all linptrs of this command.
* Only valid if cLinPtrs > 0. This field simplifies loading of saved state.
*/
int cLinPtrPages;
- /* Pointer to descriptions of linear pointers. */
+ /** Pointer to descriptions of linear pointers. */
VBOXHGCMLINPTR *paLinPtrs;
};
-static int vmmdevHGCMCmdListLock (VMMDevState *pVMMDevState)
+
+
+static int vmmdevHGCMCmdListLock (PVMMDEV pThis)
{
- int rc = RTCritSectEnter (&pVMMDevState->critsectHGCMCmdList);
+ int rc = RTCritSectEnter (&pThis->critsectHGCMCmdList);
AssertRC (rc);
return rc;
}
-static void vmmdevHGCMCmdListUnlock (VMMDevState *pVMMDevState)
+static void vmmdevHGCMCmdListUnlock (PVMMDEV pThis)
{
- int rc = RTCritSectLeave (&pVMMDevState->critsectHGCMCmdList);
+ int rc = RTCritSectLeave (&pThis->critsectHGCMCmdList);
AssertRC (rc);
}
-static int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
+static int vmmdevHGCMAddCommand (PVMMDEV pThis, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
{
- /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
+ /* PPDMDEVINS pDevIns = pThis->pDevIns; */
- int rc = vmmdevHGCMCmdListLock (pVMMDevState);
+ int rc = vmmdevHGCMCmdListLock (pThis);
if (RT_SUCCESS (rc))
{
LogFlowFunc(("%p type %d\n", pCmd, enmCmdType));
/* Insert at the head of the list. The vmmdevHGCMLoadStateDone depends on this. */
- pCmd->pNext = pVMMDevState->pHGCMCmdList;
+ pCmd->pNext = pThis->pHGCMCmdList;
pCmd->pPrev = NULL;
- if (pVMMDevState->pHGCMCmdList)
+ if (pThis->pHGCMCmdList)
{
- pVMMDevState->pHGCMCmdList->pPrev = pCmd;
+ pThis->pHGCMCmdList->pPrev = pCmd;
}
- pVMMDevState->pHGCMCmdList = pCmd;
+ pThis->pHGCMCmdList = pCmd;
pCmd->fInList = true;
@@ -158,24 +172,24 @@ static int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, R
|| enmCmdType == VBOXHGCMCMDTYPE_DISCONNECT
|| enmCmdType == VBOXHGCMCMDTYPE_CALL)
{
- Log(("vmmdevHGCMAddCommand: u32HGCMEnabled = %d\n", pVMMDevState->u32HGCMEnabled));
- if (ASMAtomicCmpXchgU32(&pVMMDevState->u32HGCMEnabled, 1, 0))
+ Log(("vmmdevHGCMAddCommand: u32HGCMEnabled = %d\n", pThis->u32HGCMEnabled));
+ if (ASMAtomicCmpXchgU32(&pThis->u32HGCMEnabled, 1, 0))
{
- VMMDevCtlSetGuestFilterMask (pVMMDevState, VMMDEV_EVENT_HGCM, 0);
+ VMMDevCtlSetGuestFilterMask (pThis, VMMDEV_EVENT_HGCM, 0);
}
}
- vmmdevHGCMCmdListUnlock (pVMMDevState);
+ vmmdevHGCMCmdListUnlock (pThis);
}
return rc;
}
-static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd)
+static int vmmdevHGCMRemoveCommand (PVMMDEV pThis, PVBOXHGCMCMD pCmd)
{
- /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
+ /* PPDMDEVINS pDevIns = pThis->pDevIns; */
- int rc = vmmdevHGCMCmdListLock (pVMMDevState);
+ int rc = vmmdevHGCMCmdListLock (pThis);
if (RT_SUCCESS (rc))
{
@@ -184,7 +198,7 @@ static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd
if (!pCmd->fInList)
{
LogFlowFunc(("%p not in the list\n", pCmd));
- vmmdevHGCMCmdListUnlock (pVMMDevState);
+ vmmdevHGCMCmdListUnlock (pThis);
return VINF_SUCCESS;
}
@@ -203,14 +217,14 @@ static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd
}
else
{
- pVMMDevState->pHGCMCmdList = pCmd->pNext;
+ pThis->pHGCMCmdList = pCmd->pNext;
}
pCmd->pNext = NULL;
pCmd->pPrev = NULL;
pCmd->fInList = false;
- vmmdevHGCMCmdListUnlock (pVMMDevState);
+ vmmdevHGCMCmdListUnlock (pThis);
}
return rc;
@@ -228,7 +242,7 @@ static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd
* @param GCPhys The physical address of the command we're looking
* for.
*/
-DECLINLINE(PVBOXHGCMCMD) vmmdevHGCMFindCommandLocked (VMMDevState *pThis, RTGCPHYS GCPhys)
+DECLINLINE(PVBOXHGCMCMD) vmmdevHGCMFindCommandLocked (PVMMDEV pThis, RTGCPHYS GCPhys)
{
for (PVBOXHGCMCMD pCmd = pThis->pHGCMCmdList;
pCmd;
@@ -250,8 +264,6 @@ static int vmmdevHGCMSaveLinPtr (PPDMDEVINS pDevIns,
{
int rc = VINF_SUCCESS;
- AssertRelease (u32Size > 0);
-
VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
/* Take the offset into the current page also into account! */
@@ -294,8 +306,6 @@ static int vmmdevHGCMSaveLinPtr (PPDMDEVINS pDevIns,
GCPtr += PAGE_SIZE;
}
- AssertRelease (iPage == cPages);
-
return rc;
}
@@ -310,7 +320,7 @@ static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
- AssertRelease (u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm);
+ AssertLogRelReturn(u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm, VERR_INVALID_PARAMETER);
RTGCPHYS GCPhysDst = pLinPtr->paPages[0] + pLinPtr->offFirstPage;
uint8_t *pu8Src = (uint8_t *)pvHost;
@@ -332,12 +342,17 @@ static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
if (cbWrite >= u32Size)
{
- PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, u32Size);
+ rc = PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, u32Size);
+ if (RT_FAILURE(rc))
+ break;
+
u32Size = 0;
break;
}
- PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, cbWrite);
+ rc = PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, cbWrite);
+ if (RT_FAILURE(rc))
+ break;
/* next */
u32Size -= cbWrite;
@@ -346,8 +361,10 @@ static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
GCPhysDst = pLinPtr->paPages[iPage];
}
- AssertRelease (iPage == pLinPtr->cPages);
- Assert(u32Size == 0);
+ if (RT_SUCCESS(rc))
+ {
+ AssertLogRelReturn(iPage == pLinPtr->cPages, VERR_INVALID_PARAMETER);
+ }
return rc;
}
@@ -473,7 +490,7 @@ static void vmmdevRestoreSavedCommand(VBOXHGCMCMD *pCmd, VBOXHGCMCMD *pSavedCmd)
pSavedCmd->paLinPtrs = NULL;
}
-int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys)
+int vmmdevHGCMConnect (PVMMDEV pThis, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys)
{
int rc = VINF_SUCCESS;
@@ -485,7 +502,7 @@ int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnec
{
VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
@@ -497,7 +514,10 @@ int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnec
Assert(pHGCMConnectCopy->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
pHGCMConnectCopy->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
- rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
+ rc = pThis->pHGCMDrv->pfnConnect (pThis->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
+
+ if (RT_FAILURE(rc))
+ vmmdevHGCMRemoveCommand(pThis, pCmd);
}
else
{
@@ -507,7 +527,7 @@ int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnec
return rc;
}
-static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
+static int vmmdevHGCMConnectSaved (PVMMDEV pThis, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
{
int rc = VINF_SUCCESS;
@@ -523,7 +543,7 @@ static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect
VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
@@ -531,12 +551,14 @@ static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect
Assert(pHGCMConnectCopy->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
pHGCMConnectCopy->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
- rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
+ rc = pThis->pHGCMDrv->pfnConnect (pThis->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
if (RT_SUCCESS (rc))
{
*pfHGCMCalled = true;
}
+ /* else
+ * ... the caller will also execute vmmdevHGCMRemoveCommand() for us */
}
else
{
@@ -546,7 +568,7 @@ static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect
return rc;
}
-int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys)
+int vmmdevHGCMDisconnect (PVMMDEV pThis, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys)
{
int rc = VINF_SUCCESS;
@@ -556,13 +578,16 @@ int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCM
if (pCmd)
{
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
pCmd->paHostParms = NULL;
pCmd->cLinPtrs = 0;
pCmd->paLinPtrs = NULL;
- rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
+ rc = pThis->pHGCMDrv->pfnDisconnect (pThis->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
+
+ if (RT_FAILURE(rc))
+ vmmdevHGCMRemoveCommand(pThis, pCmd);
}
else
{
@@ -572,7 +597,7 @@ int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCM
return rc;
}
-static int vmmdevHGCMDisconnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
+static int vmmdevHGCMDisconnectSaved (PVMMDEV pThis, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
{
int rc = VINF_SUCCESS;
@@ -585,18 +610,20 @@ static int vmmdevHGCMDisconnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMDisco
vmmdevRestoreSavedCommand(pCmd, pSavedCmd);
*ppCmd = pCmd;
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
pCmd->paHostParms = NULL;
pCmd->cLinPtrs = 0;
pCmd->paLinPtrs = NULL;
- rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
+ rc = pThis->pHGCMDrv->pfnDisconnect (pThis->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
if (RT_SUCCESS (rc))
{
*pfHGCMCalled = true;
}
+ /* else
+ * ... the caller will also execute vmmdevHGCMRemoveCommand() for us */
}
else
{
@@ -606,7 +633,7 @@ static int vmmdevHGCMDisconnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMDisco
return rc;
}
-int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32_t cbHGCMCall, RTGCPHYS GCPhys, bool f64Bits)
+int vmmdevHGCMCall (PVMMDEV pThis, VMMDevHGCMCall *pHGCMCall, uint32_t cbHGCMCall, RTGCPHYS GCPhys, bool f64Bits)
{
int rc = VINF_SUCCESS;
@@ -623,6 +650,20 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
/*
+ * Sane upper limit.
+ */
+ if (cParms > VMMDEV_MAX_HGCM_PARMS)
+ {
+ static int s_cRelWarn;
+ if (s_cRelWarn < 50)
+ {
+ s_cRelWarn++;
+ LogRel(("VMMDev: request packet with too many parameters (%d). Refusing operation.\n", cParms));
+ }
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
* Compute size of required memory buffer.
*/
@@ -654,6 +695,12 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
if (pGuestParm->u.Pointer.size > 0)
{
/* Only pointers with some actual data are counted. */
+ if (pGuestParm->u.Pointer.size > VMMDEV_MAX_HGCM_DATA_SIZE - cbCmdSize)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
cbCmdSize += pGuestParm->u.Pointer.size;
cLinPtrs++;
@@ -667,6 +714,12 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
case VMMDevHGCMParmType_PageList:
{
+ if (pGuestParm->u.PageList.size > VMMDEV_MAX_HGCM_DATA_SIZE - cbCmdSize)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
cbCmdSize += pGuestParm->u.PageList.size;
Log(("vmmdevHGCMCall: pagelist size = %d\n", pGuestParm->u.PageList.size));
} break;
@@ -706,6 +759,12 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
if (pGuestParm->u.Pointer.size > 0)
{
/* Only pointers with some actual data are counted. */
+ if (pGuestParm->u.Pointer.size > VMMDEV_MAX_HGCM_DATA_SIZE - cbCmdSize)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
cbCmdSize += pGuestParm->u.Pointer.size;
cLinPtrs++;
@@ -719,6 +778,12 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
case VMMDevHGCMParmType_PageList:
{
+ if (pGuestParm->u.PageList.size > VMMDEV_MAX_HGCM_DATA_SIZE - cbCmdSize)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
cbCmdSize += pGuestParm->u.PageList.size;
Log(("vmmdevHGCMCall: pagelist size = %d\n", pGuestParm->u.PageList.size));
} break;
@@ -787,6 +852,7 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
uint8_t *pcBuf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
pCmd->paHostParms = pHostParm;
+ pCmd->cHostParms = cParms;
uint32_t iLinPtr = 0;
RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) *cLinPtrs);
@@ -849,7 +915,7 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
{
/* Don't overdo it */
if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
- rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
+ rc = PDMDevHlpPhysReadGCVirt(pThis->pDevIns, pcBuf, linearAddr, size);
else
rc = VINF_SUCCESS;
@@ -861,7 +927,7 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
/* Remember the guest physical pages that belong to the virtual address region.
* Do it for all linear pointers because load state will require In pointer info too.
*/
- rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
+ rc = vmmdevHGCMSaveLinPtr (pThis->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
iLinPtr++;
}
@@ -911,7 +977,7 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
if (pPageListInfo->flags & VBOX_HGCM_F_PARM_DIRECTION_TO_HOST)
{
/* Copy pages to the pcBuf[size]. */
- rc = vmmdevHGCMPageListRead(pVMMDevState->pDevIns, pcBuf, size, pPageListInfo);
+ rc = vmmdevHGCMPageListRead(pThis->pDevIns, pcBuf, size, pPageListInfo);
}
else
rc = VINF_SUCCESS;
@@ -990,7 +1056,7 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
{
/* Don't overdo it */
if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
- rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
+ rc = PDMDevHlpPhysReadGCVirt(pThis->pDevIns, pcBuf, linearAddr, size);
else
rc = VINF_SUCCESS;
@@ -1002,7 +1068,7 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
/* Remember the guest physical pages that belong to the virtual address region.
* Do it for all linear pointers because load state will require In pointer info too.
*/
- rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
+ rc = vmmdevHGCMSaveLinPtr (pThis->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
iLinPtr++;
}
@@ -1052,7 +1118,7 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
if (pPageListInfo->flags & VBOX_HGCM_F_PARM_DIRECTION_TO_HOST)
{
/* Copy pages to the pcBuf[size]. */
- rc = vmmdevHGCMPageListRead(pVMMDevState->pDevIns, pcBuf, size, pPageListInfo);
+ rc = vmmdevHGCMPageListRead(pThis->pDevIns, pcBuf, size, pPageListInfo);
}
else
rc = VINF_SUCCESS;
@@ -1079,16 +1145,16 @@ int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32
if (RT_SUCCESS (rc))
{
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
/* Pass the function call to HGCM connector for actual processing */
- rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID,
+ rc = pThis->pHGCMDrv->pfnCall (pThis->pHGCMDrv, pCmd, pHGCMCall->u32ClientID,
pHGCMCall->u32Function, cParms, pCmd->paHostParms);
if (RT_FAILURE (rc))
{
Log(("vmmdevHGCMCall: pfnCall failed rc = %Rrc\n", rc));
- vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
+ vmmdevHGCMRemoveCommand (pThis, pCmd);
}
}
@@ -1118,7 +1184,7 @@ static void logRelLoadStateBufferSizeMismatch (uint32_t size, uint32_t iPage, ui
}
-static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys, uint32_t cbHGCMCall, bool f64Bits, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
+static int vmmdevHGCMCallSaved (PVMMDEV pThis, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys, uint32_t cbHGCMCall, bool f64Bits, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
{
int rc = VINF_SUCCESS;
@@ -1135,6 +1201,20 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
/*
+ * Sane upper limit.
+ */
+ if (cParms > VMMDEV_MAX_HGCM_PARMS)
+ {
+ static int s_cRelWarn;
+ if (s_cRelWarn < 50)
+ {
+ s_cRelWarn++;
+ LogRel(("VMMDev: request packet with too many parameters (%d). Refusing operation.\n", cParms));
+ }
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
* Compute size of required memory buffer.
*/
@@ -1274,7 +1354,7 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
vmmdevRestoreSavedCommand(pCmd, pSavedCmd);
*ppCmd = pCmd;
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
/* Process parameters, changing them to host context pointers for easy
* processing by connector. Guest must insure that the pointed data is actually
@@ -1289,6 +1369,7 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
uint8_t *pu8Buf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
pCmd->paHostParms = pHostParm;
+ pCmd->cHostParms = cParms;
uint32_t iParm;
int iLinPtr = 0;
@@ -1382,7 +1463,7 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
cbChunk = cbRemaining;
}
- rc = PDMDevHlpPhysRead(pVMMDevState->pDevIns,
+ rc = PDMDevHlpPhysRead(pThis->pDevIns,
pLinPtr->paPages[iPage] + offPage,
pu8Dst, cbChunk);
@@ -1451,7 +1532,7 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
if (pPageListInfo->flags & VBOX_HGCM_F_PARM_DIRECTION_TO_HOST)
{
/* Copy pages to the pcBuf[size]. */
- rc = vmmdevHGCMPageListRead(pVMMDevState->pDevIns, pu8Buf, size, pPageListInfo);
+ rc = vmmdevHGCMPageListRead(pThis->pDevIns, pu8Buf, size, pPageListInfo);
}
else
rc = VINF_SUCCESS;
@@ -1562,7 +1643,7 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
cbChunk = cbRemaining;
}
- rc = PDMDevHlpPhysRead(pVMMDevState->pDevIns,
+ rc = PDMDevHlpPhysRead(pThis->pDevIns,
pLinPtr->paPages[iPage] + offPage,
pu8Dst, cbChunk);
@@ -1631,7 +1712,7 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
if (pPageListInfo->flags & VBOX_HGCM_F_PARM_DIRECTION_TO_HOST)
{
/* Copy pages to the pcBuf[size]. */
- rc = vmmdevHGCMPageListRead(pVMMDevState->pDevIns, pu8Buf, size, pPageListInfo);
+ rc = vmmdevHGCMPageListRead(pThis->pDevIns, pu8Buf, size, pPageListInfo);
}
else
rc = VINF_SUCCESS;
@@ -1659,11 +1740,13 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
if (RT_SUCCESS (rc))
{
/* Pass the function call to HGCM connector for actual processing */
- rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
+ rc = pThis->pHGCMDrv->pfnCall (pThis->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
if (RT_SUCCESS (rc))
{
*pfHGCMCalled = true;
}
+ /* else
+ * ... the caller will also execute vmmdevHGCMRemoveCommand() for us */
}
return rc;
@@ -1674,10 +1757,10 @@ static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCM
*
* @thread EMT
*/
-int vmmdevHGCMCancel (VMMDevState *pVMMDevState, VMMDevHGCMCancel *pHGCMCancel, RTGCPHYS GCPhys)
+int vmmdevHGCMCancel (PVMMDEV pThis, VMMDevHGCMCancel *pHGCMCancel, RTGCPHYS GCPhys)
{
NOREF(pHGCMCancel);
- int rc = vmmdevHGCMCancel2(pVMMDevState, GCPhys);
+ int rc = vmmdevHGCMCancel2(pThis, GCPhys);
return rc == VERR_NOT_FOUND ? VERR_INVALID_PARAMETER : rc;
}
@@ -1693,7 +1776,7 @@ int vmmdevHGCMCancel (VMMDevState *pVMMDevState, VMMDevHGCMCancel *pHGCMCancel,
*
* @thread EMT
*/
-int vmmdevHGCMCancel2 (VMMDevState *pThis, RTGCPHYS GCPhys)
+int vmmdevHGCMCancel2 (PVMMDEV pThis, RTGCPHYS GCPhys)
{
if ( GCPhys == 0
|| GCPhys == NIL_RTGCPHYS
@@ -1758,11 +1841,91 @@ static int vmmdevHGCMCmdVerify (PVBOXHGCMCMD pCmd, VMMDevHGCMRequestHeader *pHea
return VERR_INVALID_PARAMETER;
}
-#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, IHGCMPort)) )
+#ifdef VBOX_WITH_64_BITS_GUESTS
+static int vmmdevHGCMParmVerify64(HGCMFunctionParameter64 *pGuestParm, VBOXHGCMSVCPARM *pHostParm)
+{
+ int rc = VERR_INVALID_PARAMETER;
+
+ switch (pGuestParm->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ if (pHostParm->type == VBOX_HGCM_SVC_PARM_32BIT)
+ rc = VINF_SUCCESS;
+ break;
+
+ case VMMDevHGCMParmType_64bit:
+ if (pHostParm->type == VBOX_HGCM_SVC_PARM_64BIT)
+ rc = VINF_SUCCESS;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
+ case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
+ case VMMDevHGCMParmType_LinAddr: /* In & Out */
+ if ( pHostParm->type == VBOX_HGCM_SVC_PARM_PTR
+ && pGuestParm->u.Pointer.size >= pHostParm->u.pointer.size)
+ rc = VINF_SUCCESS;
+ break;
+
+ case VMMDevHGCMParmType_PageList:
+ if ( pHostParm->type == VBOX_HGCM_SVC_PARM_PTR
+ && pGuestParm->u.PageList.size >= pHostParm->u.pointer.size)
+ rc = VINF_SUCCESS;
+ break;
+
+ default:
+ AssertLogRelMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
+ break;
+ }
+
+ return rc;
+}
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+
+#ifdef VBOX_WITH_64_BITS_GUESTS
+static int vmmdevHGCMParmVerify32(HGCMFunctionParameter32 *pGuestParm, VBOXHGCMSVCPARM *pHostParm)
+#else
+static int vmmdevHGCMParmVerify32(HGCMFunctionParameter *pGuestParm, VBOXHGCMSVCPARM *pHostParm)
+#endif
+{
+ int rc = VERR_INVALID_PARAMETER;
+
+ switch (pGuestParm->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ if (pHostParm->type == VBOX_HGCM_SVC_PARM_32BIT)
+ rc = VINF_SUCCESS;
+ break;
+
+ case VMMDevHGCMParmType_64bit:
+ if (pHostParm->type == VBOX_HGCM_SVC_PARM_64BIT)
+ rc = VINF_SUCCESS;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
+ case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
+ case VMMDevHGCMParmType_LinAddr: /* In & Out */
+ if ( pHostParm->type == VBOX_HGCM_SVC_PARM_PTR
+ && pGuestParm->u.Pointer.size >= pHostParm->u.pointer.size)
+ rc = VINF_SUCCESS;
+ break;
+
+ case VMMDevHGCMParmType_PageList:
+ if ( pHostParm->type == VBOX_HGCM_SVC_PARM_PTR
+ && pGuestParm->u.PageList.size >= pHostParm->u.pointer.size)
+ rc = VINF_SUCCESS;
+ break;
+
+ default:
+ AssertLogRelMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
+ break;
+ }
+
+ return rc;
+}
DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
{
- VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDevState, IHGCMPort);
#ifdef VBOX_WITH_DTRACE
uint32_t idFunction = 0;
uint32_t idClient = 0;
@@ -1790,7 +1953,7 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
* back to guest memory.
*/
VBOXDD_HGCMCALL_COMPLETED_EMT(pCmd, result);
- vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
+ vmmdevHGCMRemoveCommand (pThis, pCmd);
if (pCmd->fCancelled || pCmd->fSaved)
{
@@ -1830,15 +1993,14 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
* the request. (This isn't 100% optimal, but it solves the
* 3.0 blocker.)
*/
- /** @todo s/pVMMDevState/pThis/g */
/** @todo It would be faster if this interface would use MMIO2 memory and we
* didn't have to mess around with PDMDevHlpPhysRead/Write. We're
* reading the header 3 times now and writing the request back twice. */
- PDMCritSectEnter(&pVMMDevState->CritSect, VERR_SEM_BUSY);
- PDMCritSectLeave(&pVMMDevState->CritSect);
+ PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ PDMCritSectLeave(&pThis->CritSect);
- PDMDevHlpPhysRead(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
+ PDMDevHlpPhysRead(pThis->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
/* Setup return codes. */
pHeader->result = result;
@@ -1858,6 +2020,8 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
uint32_t cParms = pHGCMCall->cParms;
+ if (cParms != pCmd->cHostParms)
+ rc = VERR_INVALID_PARAMETER;
VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
@@ -1866,8 +2030,12 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
- for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
+ for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
{
+ rc = vmmdevHGCMParmVerify64(pGuestParm, pHostParm);
+ if (RT_FAILURE(rc))
+ break;
+
switch (pGuestParm->type)
{
case VMMDevHGCMParmType_32bit:
@@ -1892,9 +2060,8 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
{
/* Use the saved page list to write data back to the guest RAM. */
- rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr,
+ rc = vmmdevHGCMWriteLinPtr (pThis->pDevIns, i, pHostParm->u.pointer.addr,
size, iLinPtr, pCmd->paLinPtrs);
- AssertReleaseRC(rc);
}
/* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
@@ -1933,7 +2100,7 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
if (pPageListInfo->flags & VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST)
{
/* Copy pHostParm->u.pointer.addr[pHostParm->u.pointer.size] to pages. */
- rc = vmmdevHGCMPageListWrite(pVMMDevState->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
+ rc = vmmdevHGCMPageListWrite(pThis->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
}
else
rc = VINF_SUCCESS;
@@ -1945,7 +2112,8 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
default:
{
/* This indicates that the guest request memory was corrupted. */
- AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
+ rc = VERR_INVALID_PARAMETER;
+ break;
}
}
}
@@ -1961,6 +2129,8 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
uint32_t cParms = pHGCMCall->cParms;
+ if (cParms != pCmd->cHostParms)
+ rc = VERR_INVALID_PARAMETER;
VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
@@ -1969,8 +2139,12 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
- for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
+ for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
{
+ rc = vmmdevHGCMParmVerify32(pGuestParm, pHostParm);
+ if (RT_FAILURE(rc))
+ break;
+
switch (pGuestParm->type)
{
case VMMDevHGCMParmType_32bit:
@@ -1995,8 +2169,7 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
{
/* Use the saved page list to write data back to the guest RAM. */
- rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
- AssertReleaseRC(rc);
+ rc = vmmdevHGCMWriteLinPtr (pThis->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
}
/* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
@@ -2035,7 +2208,7 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
if (pPageListInfo->flags & VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST)
{
/* Copy pHostParm->u.pointer.addr[pHostParm->u.pointer.size] to pages. */
- rc = vmmdevHGCMPageListWrite(pVMMDevState->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
+ rc = vmmdevHGCMPageListWrite(pThis->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
}
else
rc = VINF_SUCCESS;
@@ -2047,7 +2220,8 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
default:
{
/* This indicates that the guest request memory was corrupted. */
- AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
+ rc = VERR_INVALID_PARAMETER;
+ break;
}
}
}
@@ -2063,6 +2237,8 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
uint32_t cParms = pHGCMCall->cParms;
+ if (cParms != pCmd->cHostParms)
+ rc = VERR_INVALID_PARAMETER;
VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
@@ -2071,8 +2247,12 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
- for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
+ for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
{
+ rc = vmmdevHGCMParmVerify32(pGuestParm, pHostParm);
+ if (RT_FAILURE(rc))
+ break;
+
switch (pGuestParm->type)
{
case VMMDevHGCMParmType_32bit:
@@ -2097,8 +2277,7 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
{
/* Use the saved page list to write data back to the guest RAM. */
- rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
- AssertReleaseRC(rc);
+ rc = vmmdevHGCMWriteLinPtr (pThis->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
}
/* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
@@ -2137,7 +2316,7 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
if (pPageListInfo->flags & VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST)
{
/* Copy pHostParm->u.pointer.addr[pHostParm->u.pointer.size] to pages. */
- rc = vmmdevHGCMPageListWrite(pVMMDevState->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
+ rc = vmmdevHGCMPageListWrite(pThis->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
}
else
rc = VINF_SUCCESS;
@@ -2149,7 +2328,8 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
default:
{
/* This indicates that the guest request memory was corrupted. */
- AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
+ rc = VERR_INVALID_PARAMETER;
+ break;
}
}
}
@@ -2175,20 +2355,21 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
break;
}
}
- else
+
+ if (RT_FAILURE(rc))
{
- /* Command type is wrong. Return error to the guest. */
- pHeader->header.rc = rc;
+ /* Command is wrong. Return HGCM error result to the guest. */
+ pHeader->result = rc;
}
/* Mark request as processed. */
pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
/* Write back the request */
- PDMDevHlpPhysWrite(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
+ PDMDevHlpPhysWrite(pThis->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
/* Now, when the command was removed from the internal list, notify the guest. */
- VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
+ VMMDevNotifyGuest (pThis, VMMDEV_EVENT_HGCM);
if ((uint8_t *)pHeader != &au8Prealloc[0])
{
@@ -2211,20 +2392,20 @@ DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result
DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
{
- VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
+ PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDevState, IHGCMPort);
VBOXDD_HGCMCALL_COMPLETED_REQ(pCmd, result);
/** @todo no longer necessary to forward to EMT, but it might be more
* efficient...? */
/* Not safe to execute asynchronously; forward to EMT */
- int rc = VMR3ReqCallVoidNoWait(PDMDevHlpGetVM(pVMMDevState->pDevIns), VMCPUID_ANY,
+ int rc = VMR3ReqCallVoidNoWait(PDMDevHlpGetVM(pThis->pDevIns), VMCPUID_ANY,
(PFNRT)hgcmCompletedWorker, 3, pInterface, result, pCmd);
AssertRC(rc);
}
-/* @thread EMT */
-int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
+/** @thread EMT */
+int vmmdevHGCMSaveState(PVMMDEV pThis, PSSMHANDLE pSSM)
{
/* Save information about pending requests.
* Only GCPtrs are of interest.
@@ -2236,7 +2417,7 @@ int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
/* Compute how many commands are pending. */
uint32_t cCmds = 0;
- PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
+ PVBOXHGCMCMD pIter = pThis->pHGCMCmdList;
while (pIter)
{
@@ -2253,7 +2434,7 @@ int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
if (cCmds > 0)
{
- pIter = pVMMDevState->pHGCMCmdList;
+ pIter = pThis->pHGCMCmdList;
while (pIter)
{
@@ -2330,7 +2511,7 @@ int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
* completed later by a still running host service.
*/
pIter->fSaved = true;
- vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
+ vmmdevHGCMRemoveCommand (pThis, pIter);
pIter = pNext;
}
@@ -2344,7 +2525,7 @@ int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
}
/** @thread EMT(0) */
-int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM, uint32_t uVersion)
+int vmmdevHGCMLoadState(PVMMDEV pThis, PSSMHANDLE pSSM, uint32_t uVersion)
{
int rc = VINF_SUCCESS;
@@ -2378,7 +2559,7 @@ int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM, uint32_t uVe
pCmd->enmCmdType = VBOXHGCMCMDTYPE_LOADSTATE; /* This marks the "old" saved command. */
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
}
}
else
@@ -2500,7 +2681,7 @@ int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM, uint32_t uVe
rc = SSMR3GetU32(pSSM, &u32);
AssertRCReturn(rc, rc);
- vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
+ vmmdevHGCMAddCommand (pThis, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
}
/* A reserved field, will allow to extend saved data for VMMDevHGCM. */
@@ -2511,15 +2692,15 @@ int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM, uint32_t uVe
return rc;
}
-/* @thread EMT */
-int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
+/** @thread EMT */
+int vmmdevHGCMLoadStateDone(PVMMDEV pThis, PSSMHANDLE pSSM)
{
LogFlowFunc(("\n"));
/* Reissue pending requests. */
- PPDMDEVINS pDevIns = pVMMDevState->pDevIns;
+ PPDMDEVINS pDevIns = pThis->pDevIns;
- int rc = vmmdevHGCMCmdListLock (pVMMDevState);
+ int rc = vmmdevHGCMCmdListLock (pThis);
if (RT_SUCCESS (rc))
{
@@ -2533,9 +2714,9 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
* resubmitting the command to HGCM services.
* New commands will be inserted to the list.
*/
- PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
+ PVBOXHGCMCMD pIter = pThis->pHGCMCmdList;
- pVMMDevState->pHGCMCmdList = NULL; /* Reset the list. Saved commands will be processed and deallocated. */
+ pThis->pHGCMCmdList = NULL; /* Reset the list. Saved commands will be processed and deallocated. */
while (pIter)
{
@@ -2583,7 +2764,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
requestHeader->header.rc = VERR_INVALID_PARAMETER;
}
- else if (!pVMMDevState->pHGCMDrv)
+ else if (!pThis->pHGCMDrv)
{
Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
requestHeader->header.rc = VERR_NOT_SUPPORTED;
@@ -2594,7 +2775,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
Log(("VMMDevReq_HGCMConnect\n"));
- requestHeader->header.rc = vmmdevHGCMConnectSaved (pVMMDevState, pHGCMConnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
+ requestHeader->header.rc = vmmdevHGCMConnectSaved (pThis, pHGCMConnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
}
break;
}
@@ -2606,7 +2787,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
requestHeader->header.rc = VERR_INVALID_PARAMETER;
}
- else if (!pVMMDevState->pHGCMDrv)
+ else if (!pThis->pHGCMDrv)
{
Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
requestHeader->header.rc = VERR_NOT_SUPPORTED;
@@ -2616,7 +2797,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
- requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pVMMDevState, pHGCMDisconnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
+ requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pThis, pHGCMDisconnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
}
break;
}
@@ -2628,7 +2809,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
requestHeader->header.rc = VERR_INVALID_PARAMETER;
}
- else if (!pVMMDevState->pHGCMDrv)
+ else if (!pThis->pHGCMDrv)
{
Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
requestHeader->header.rc = VERR_NOT_SUPPORTED;
@@ -2646,7 +2827,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
#else
bool f64Bits = false;
#endif /* VBOX_WITH_64_BITS_GUESTS */
- requestHeader->header.rc = vmmdevHGCMCallSaved (pVMMDevState, pHGCMCall, pIter->GCPhys, requestHeader->header.size, f64Bits, &fHGCMCalled, pIter, &pCmd);
+ requestHeader->header.rc = vmmdevHGCMCallSaved (pThis, pHGCMCall, pIter->GCPhys, requestHeader->header.size, f64Bits, &fHGCMCalled, pIter, &pCmd);
}
break;
}
@@ -2662,7 +2843,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
requestHeader->header.rc = VERR_INVALID_PARAMETER;
}
- else if (!pVMMDevState->pHGCMDrv)
+ else if (!pThis->pHGCMDrv)
{
Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
requestHeader->header.rc = VERR_NOT_SUPPORTED;
@@ -2673,7 +2854,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
Log(("VMMDevReq_HGCMConnect\n"));
- requestHeader->header.rc = vmmdevHGCMConnect (pVMMDevState, pHGCMConnect, pIter->GCPhys);
+ requestHeader->header.rc = vmmdevHGCMConnect (pThis, pHGCMConnect, pIter->GCPhys);
}
break;
}
@@ -2685,7 +2866,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
requestHeader->header.rc = VERR_INVALID_PARAMETER;
}
- else if (!pVMMDevState->pHGCMDrv)
+ else if (!pThis->pHGCMDrv)
{
Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
requestHeader->header.rc = VERR_NOT_SUPPORTED;
@@ -2695,7 +2876,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
- requestHeader->header.rc = vmmdevHGCMDisconnect (pVMMDevState, pHGCMDisconnect, pIter->GCPhys);
+ requestHeader->header.rc = vmmdevHGCMDisconnect (pThis, pHGCMDisconnect, pIter->GCPhys);
}
break;
}
@@ -2712,7 +2893,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
requestHeader->header.rc = VERR_INVALID_PARAMETER;
}
- else if (!pVMMDevState->pHGCMDrv)
+ else if (!pThis->pHGCMDrv)
{
Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
requestHeader->header.rc = VERR_NOT_SUPPORTED;
@@ -2730,7 +2911,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
#else
bool f64Bits = false;
#endif /* VBOX_WITH_64_BITS_GUESTS */
- requestHeader->header.rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, requestHeader->header.size, pIter->GCPhys, f64Bits);
+ requestHeader->header.rc = vmmdevHGCMCall (pThis, pHGCMCall, requestHeader->header.size, pIter->GCPhys, f64Bits);
}
break;
}
@@ -2775,7 +2956,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
/* HGCM was not called. Deallocate the current command and then notify guest. */
if (pCmd)
{
- vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
+ vmmdevHGCMRemoveCommand (pThis, pCmd);
if (pCmd->paLinPtrs != NULL)
{
@@ -2786,7 +2967,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
pCmd = NULL;
}
- VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
+ VMMDevNotifyGuest (pThis, VMMDEV_EVENT_HGCM);
}
}
@@ -2801,7 +2982,7 @@ int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
pIter = pNext;
}
- vmmdevHGCMCmdListUnlock (pVMMDevState);
+ vmmdevHGCMCmdListUnlock (pThis);
}
return rc;
diff --git a/src/VBox/Devices/VMMDev/VMMDevHGCM.h b/src/VBox/Devices/VMMDev/VMMDevHGCM.h
index 0cc2b95f..6ec1cd37 100644
--- a/src/VBox/Devices/VMMDev/VMMDevHGCM.h
+++ b/src/VBox/Devices/VMMDev/VMMDevHGCM.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/VMMDev/VMMDevState.h b/src/VBox/Devices/VMMDev/VMMDevState.h
index c6299556..b04c0cda 100644
--- a/src/VBox/Devices/VMMDev/VMMDevState.h
+++ b/src/VBox/Devices/VMMDev/VMMDevState.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,8 +21,11 @@
#include <VBox/VMMDev.h>
#include <VBox/vmm/pdmdev.h>
#include <VBox/vmm/pdmifs.h>
+#ifndef VBOX_WITHOUT_TESTING_FEATURES
+# include <iprt/test.h>
+#endif
-#define TIMESYNC_BACKDOOR
+#define VMMDEV_WITH_ALT_TIMESYNC
typedef struct DISPLAYCHANGEINFO
{
@@ -30,6 +33,10 @@ typedef struct DISPLAYCHANGEINFO
uint32_t yres;
uint32_t bpp;
uint32_t display;
+ int32_t xOrigin;
+ int32_t yOrigin;
+ bool fEnabled;
+ bool fChangeOrigin;
} DISPLAYCHANGEINFO;
typedef struct DISPLAYCHANGEREQUEST
@@ -49,7 +56,7 @@ typedef struct DISPLAYCHANGEDATA
bool fGuestSentChangeEventAck;
bool afAlignment[3];
- DISPLAYCHANGEREQUEST aRequests[64]; // @todo maxMonitors
+ DISPLAYCHANGEREQUEST aRequests[64]; /// @todo maxMonitors
} DISPLAYCHANGEDATA;
@@ -88,6 +95,7 @@ typedef struct VMMDEVFACILITYSTATUSENTRY
/** The facility, see VBoxGuestFacilityType. */
uint32_t uFacility;
/** The status, see VBoxGuestFacilityStatus. */
+ /** @todo r=andy uint16_t vs. uint32_t (VBoxGuestFacilityStatus enum). */
uint16_t uStatus;
/** Whether this entry is fixed and cannot be reused when inactive. */
bool fFixed;
@@ -108,10 +116,12 @@ typedef VMMDEVFACILITYSTATUSENTRY *PVMMDEVFACILITYSTATUSENTRY;
typedef struct VMMDevState
{
/** The PCI device structure. */
- PCIDevice dev;
-
- /** The critical section for this device. */
- PDMCRITSECT CritSect;
+ PCIDevice PciDev;
+ /** The critical section for this device.
+ * @remarks We use this rather than the default one, it's simpler with all
+ * the driver interfaces where we have to waste time digging out the
+ * PDMDEVINS structure. */
+ PDMCRITSECT CritSect;
/** hypervisor address space size */
uint32_t hypervisorSize;
@@ -151,19 +161,16 @@ typedef struct VMMDevState
char szMsg[512];
/** message buffer index. */
uint32_t iMsg;
- /** Base port in the assigned I/O space. */
- RTIOPORT PortBase;
- /** Alignment padding. */
- RTIOPORT PortAlignment2;
+ /** Alignment padding. */
+ uint32_t u32Alignment2;
/** IRQ number assigned to the device */
uint32_t irq;
/** Current host side event flags */
uint32_t u32HostEventFlags;
- /** Mask of events guest is interested in. Note that the HGCM events
- * are enabled automatically by the VMMDev device when guest issues
- * HGCM commands.
- */
+ /** Mask of events guest is interested in.
+ * @note The HGCM events are enabled automatically by the VMMDev device when
+ * guest issues HGCM commands. */
uint32_t u32GuestFilterMask;
/** Delayed mask of guest events */
uint32_t u32NewGuestFilterMask;
@@ -221,7 +228,9 @@ typedef struct VMMDevState
bool afAlignment4[HC_ARCH_BITS == 32 ? 3 : 7];
/* memory balloon change request */
- uint32_t u32MemoryBalloonSize, u32LastMemoryBalloonSize;
+ uint32_t cMbMemoryBalloon;
+ /** The last balloon size queried by the guest additions. */
+ uint32_t cMbMemoryBalloonLast;
/* guest ram size */
uint64_t cbGuestRAM;
@@ -237,9 +246,9 @@ typedef struct VMMDevState
bool afAlignment5[1];
bool fVRDPEnabled;
- uint32_t u32VRDPExperienceLevel;
+ uint32_t uVRDPExperienceLevel;
-#ifdef TIMESYNC_BACKDOOR
+#ifdef VMMDEV_WITH_ALT_TIMESYNC
uint64_t hostTime;
bool fTimesyncBackdoorLo;
bool afAlignment6[3];
@@ -307,8 +316,10 @@ typedef struct VMMDevState
bool fRZEnabled;
/** Set if testing is enabled. */
bool fTestingEnabled;
+ /** Set if testing the MMIO testing range is enabled. */
+ bool fTestingMMIO;
/** Alignment padding. */
- bool afPadding9[HC_ARCH_BITS == 32 ? 2 : 6];
+ bool afPadding9[HC_ARCH_BITS == 32 ? 1 : 5];
#ifndef VBOX_WITHOUT_TESTING_FEATURES
/** The high timestamp value. */
uint32_t u32TestingHighTimestamp;
@@ -342,21 +353,26 @@ typedef struct VMMDevState
char szName[1024 - 8 - 4];
} Value;
} TestingData;
+ /** The XML output file name (can be a named pipe, doesn't matter to us). */
+ R3PTRTYPE(char *) pszTestingXmlOutput;
+ /** Testing instance for dealing with the output. */
+ RTTEST hTestingTest;
#endif /* !VBOX_WITHOUT_TESTING_FEATURES */
} VMMDevState;
-AssertCompileMemberAlignment(VMMDevState, CritSect, 8);
-AssertCompileMemberAlignment(VMMDevState, cbGuestRAM, 8);
-AssertCompileMemberAlignment(VMMDevState, enmCpuHotPlugEvent, 4);
-AssertCompileMemberAlignment(VMMDevState, aFacilityStatuses, 8);
+typedef VMMDevState VMMDEV;
+/** Pointer to the VMM device state. */
+typedef VMMDEV *PVMMDEV;
+AssertCompileMemberAlignment(VMMDEV, CritSect, 8);
+AssertCompileMemberAlignment(VMMDEV, cbGuestRAM, 8);
+AssertCompileMemberAlignment(VMMDEV, enmCpuHotPlugEvent, 4);
+AssertCompileMemberAlignment(VMMDEV, aFacilityStatuses, 8);
#ifndef VBOX_WITHOUT_TESTING_FEATURES
-AssertCompileMemberAlignment(VMMDevState, TestingData.Value.u64Value, 8);
+AssertCompileMemberAlignment(VMMDEV, TestingData.Value.u64Value, 8);
#endif
-void VMMDevNotifyGuest (VMMDevState *pVMMDevState, uint32_t u32EventMask);
-void VMMDevCtlSetGuestFilterMask (VMMDevState *pVMMDevState,
- uint32_t u32OrMask,
- uint32_t u32NotMask);
+void VMMDevNotifyGuest(VMMDEV *pVMMDevState, uint32_t u32EventMask);
+void VMMDevCtlSetGuestFilterMask(VMMDEV *pVMMDevState, uint32_t u32OrMask, uint32_t u32NotMask);
#endif /* !___VMMDev_VMMDevState_h */
diff --git a/src/VBox/Devices/VMMDev/VMMDevTesting.cpp b/src/VBox/Devices/VMMDev/VMMDevTesting.cpp
index 8f5d64d2..220f4792 100644
--- a/src/VBox/Devices/VMMDev/VMMDevTesting.cpp
+++ b/src/VBox/Devices/VMMDev/VMMDevTesting.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2010-2012 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,9 +31,7 @@
#include <iprt/assert.h>
#include <iprt/string.h>
#include <iprt/time.h>
-#ifdef IN_RING3
-# include <iprt/stream.h>
-#endif
+#include <iprt/test.h>
#include "VMMDevState.h"
#include "VMMDevTesting.h"
@@ -46,7 +44,6 @@
{ \
LogAlways(a);\
LogRel(a);\
- RTPrintf a; \
} while (0)
/**
@@ -133,22 +130,23 @@ static void vmmdevTestingCmdExec_ValueReg(PPDMDEVINS pDevIns, VMMDevState *pThis
size_t const cchValueNm = strlen(pszValueNm);
if (cchValueNm && pszRegNm && *pszRegNm)
{
- PVM pVM = PDMDevHlpGetVM(pDevIns);
+ PUVM pUVM = PDMDevHlpGetUVM(pDevIns);
+ PVM pVM = PDMDevHlpGetVM(pDevIns);
VMCPUID idCpu = VMMGetCpuId(pVM);
uint64_t u64Value;
- int rc2 = DBGFR3RegNmQueryU64(pVM, idCpu, pszRegNm, &u64Value);
+ int rc2 = DBGFR3RegNmQueryU64(pUVM, idCpu, pszRegNm, &u64Value);
if (RT_SUCCESS(rc2))
{
const char *pszWarn = rc2 == VINF_DBGF_TRUNCATED_REGISTER ? " truncated" : "";
#if 1 /*!RTTestValue format*/
char szFormat[128], szValue[128];
RTStrPrintf(szFormat, sizeof(szFormat), "%%VR{%s}", pszRegNm);
- rc2 = DBGFR3RegPrintf(pVM, idCpu, szValue, sizeof(szValue), szFormat);
+ rc2 = DBGFR3RegPrintf(pUVM, idCpu, szValue, sizeof(szValue), szFormat);
if (RT_SUCCESS(rc2))
VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %16s {reg=%s}%s\n",
pszValueNm,
(ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "",
- szValue, pszRegNm));
+ szValue, pszRegNm, pszWarn));
else
#endif
VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [0] {reg=%s}%s\n",
@@ -233,23 +231,36 @@ PDMBOTHCBDECL(int) vmmdevTestingIoWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPO
else
{
#ifdef IN_RING3
+ pThis->TestingData.String.sz[off] = '\0';
switch (uCmd)
{
case VMMDEV_TESTING_CMD_INIT:
- VMMDEV_TESTING_OUTPUT(("testing: INIT '%.*s'\n",
- sizeof(pThis->TestingData.String.sz) - 1, pThis->TestingData.String.sz));
+ VMMDEV_TESTING_OUTPUT(("testing: INIT '%s'\n", pThis->TestingData.String.sz));
+ if (pThis->hTestingTest != NIL_RTTEST)
+ {
+ RTTestChangeName(pThis->hTestingTest, pThis->TestingData.String.sz);
+ RTTestBanner(pThis->hTestingTest);
+ }
break;
case VMMDEV_TESTING_CMD_SUB_NEW:
- VMMDEV_TESTING_OUTPUT(("testing: SUB_NEW '%.*s'\n",
- sizeof(pThis->TestingData.String.sz) - 1, pThis->TestingData.String.sz));
+ VMMDEV_TESTING_OUTPUT(("testing: SUB_NEW '%s'\n", pThis->TestingData.String.sz));
+ if (pThis->hTestingTest != NIL_RTTEST)
+ RTTestSub(pThis->hTestingTest, pThis->TestingData.String.sz);
break;
case VMMDEV_TESTING_CMD_FAILED:
- VMMDEV_TESTING_OUTPUT(("testing: FAILED '%.*s'\n",
- sizeof(pThis->TestingData.String.sz) - 1, pThis->TestingData.String.sz));
+ if (pThis->hTestingTest != NIL_RTTEST)
+ RTTestFailed(pThis->hTestingTest, "%s", pThis->TestingData.String.sz);
+ VMMDEV_TESTING_OUTPUT(("testing: FAILED '%s'\n", pThis->TestingData.String.sz));
break;
case VMMDEV_TESTING_CMD_SKIPPED:
- VMMDEV_TESTING_OUTPUT(("testing: SKIPPED '%.*s'\n",
- sizeof(pThis->TestingData.String.sz) - 1, pThis->TestingData.String.sz));
+ if (pThis->hTestingTest != NIL_RTTEST)
+ {
+ if (off)
+ RTTestSkipped(pThis->hTestingTest, "%s", pThis->TestingData.String.sz);
+ else
+ RTTestSkipped(pThis->hTestingTest, NULL);
+ }
+ VMMDEV_TESTING_OUTPUT(("testing: SKIPPED '%s'\n", pThis->TestingData.String.sz));
break;
}
#else
@@ -268,9 +279,27 @@ PDMBOTHCBDECL(int) vmmdevTestingIoWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPO
#ifdef IN_RING3
pThis->TestingData.Error.c = u32;
if (uCmd == VMMDEV_TESTING_CMD_TERM)
+ {
+ if (pThis->hTestingTest != NIL_RTTEST)
+ {
+ while (RTTestErrorCount(pThis->hTestingTest) < u32)
+ RTTestErrorInc(pThis->hTestingTest); /* A bit stupid, but does the trick. */
+ RTTestSubDone(pThis->hTestingTest);
+ RTTestSummaryAndDestroy(pThis->hTestingTest);
+ pThis->hTestingTest = NIL_RTTEST;
+ }
VMMDEV_TESTING_OUTPUT(("testing: TERM - %u errors\n", u32));
+ }
else
+ {
+ if (pThis->hTestingTest != NIL_RTTEST)
+ {
+ while (RTTestSubErrorCount(pThis->hTestingTest) < u32)
+ RTTestErrorInc(pThis->hTestingTest); /* A bit stupid, but does the trick. */
+ RTTestSubDone(pThis->hTestingTest);
+ }
VMMDEV_TESTING_OUTPUT(("testing: SUB_DONE - %u errors\n", u32));
+ }
return VINF_SUCCESS;
#else
return VINF_IOM_R3_IOPORT_WRITE;
@@ -294,7 +323,7 @@ PDMBOTHCBDECL(int) vmmdevTestingIoWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPO
}
if ( off >= 12
&& cb == 1
- && off < sizeof(pThis->TestingData.Value.szName) - 1 - 12)
+ && off - 12 < sizeof(pThis->TestingData.Value.szName) - 1)
{
if (u32)
{
@@ -304,8 +333,20 @@ PDMBOTHCBDECL(int) vmmdevTestingIoWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPO
else
{
#ifdef IN_RING3
- VMMDEV_TESTING_OUTPUT(("testing: VALUE '%.*s'%*s: %'9llu (%#llx) [%u]\n",
- sizeof(pThis->TestingData.Value.szName) - 1, pThis->TestingData.Value.szName,
+ pThis->TestingData.Value.szName[off - 12] = '\0';
+
+ RTTESTUNIT enmUnit = (RTTESTUNIT)pThis->TestingData.Value.u32Unit;
+ if (enmUnit <= RTTESTUNIT_INVALID || enmUnit >= RTTESTUNIT_END)
+ {
+ VMMDEV_TESTING_OUTPUT(("Invalid log value unit %#x\n", pThis->TestingData.Value.u32Unit));
+ enmUnit = RTTESTUNIT_NONE;
+ }
+ if (pThis->hTestingTest != NIL_RTTEST)
+ RTTestValue(pThis->hTestingTest, pThis->TestingData.Value.szName,
+ pThis->TestingData.Value.u64Value.u, enmUnit);
+
+ VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [%u]\n",
+ pThis->TestingData.Value.szName,
off - 12 > 48 ? 0 : 48 - (off - 12), "",
pThis->TestingData.Value.u64Value.u, pThis->TestingData.Value.u64Value.u,
pThis->TestingData.Value.u32Unit));
@@ -314,17 +355,6 @@ PDMBOTHCBDECL(int) vmmdevTestingIoWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPO
#endif
}
return VINF_SUCCESS;
-
-#ifdef IN_RING3
- pThis->TestingData.Error.c = u32;
- if (uCmd == VMMDEV_TESTING_CMD_TERM)
- VMMDEV_TESTING_OUTPUT(("testing: TERM - %u errors\n", u32));
- else
- VMMDEV_TESTING_OUTPUT(("testing: SUB_DONE - %u errors\n", u32));
- return VINF_SUCCESS;
-#else
- return VINF_IOM_R3_IOPORT_WRITE;
-#endif
}
break;
@@ -441,28 +471,54 @@ PDMBOTHCBDECL(int) vmmdevTestingIoRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPOR
* @returns VBox status code.
* @param pDevIns The VMMDev device instance.
*/
+void vmmdevTestingTerminate(PPDMDEVINS pDevIns)
+{
+ VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
+ if (!pThis->fTestingEnabled)
+ return;
+
+ if (pThis->hTestingTest != NIL_RTTEST)
+ {
+ RTTestFailed(pThis->hTestingTest, "Still open at vmmdev destruction.");
+ RTTestSummaryAndDestroy(pThis->hTestingTest);
+ pThis->hTestingTest = NIL_RTTEST;
+ }
+}
+
+
+/**
+ * Initializes the testing part of the VMMDev if enabled.
+ *
+ * @returns VBox status code.
+ * @param pDevIns The VMMDev device instance.
+ */
int vmmdevTestingInitialize(PPDMDEVINS pDevIns)
{
VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
+ int rc;
+
if (!pThis->fTestingEnabled)
return VINF_SUCCESS;
- /*
- * Register a chunk of MMIO memory that we'll use for various
- * tests interfaces.
- */
- int rc = PDMDevHlpMMIORegister(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE, NULL /*pvUser*/,
+ if (pThis->fTestingMMIO)
+ {
+ /*
+ * Register a chunk of MMIO memory that we'll use for various
+ * tests interfaces. Optional, needs to be explicitly enabled.
+ */
+ rc = PDMDevHlpMMIORegister(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE, NULL /*pvUser*/,
IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
vmmdevTestingMmioWrite, vmmdevTestingMmioRead, "VMMDev Testing");
- AssertRCReturn(rc, rc);
- if (pThis->fRZEnabled)
- {
- rc = PDMDevHlpMMIORegisterR0(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE, NIL_RTR0PTR /*pvUser*/,
- "vmmdevTestingMmioWrite", "vmmdevTestingMmioRead");
- AssertRCReturn(rc, rc);
- rc = PDMDevHlpMMIORegisterRC(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE, NIL_RTRCPTR /*pvUser*/,
- "vmmdevTestingMmioWrite", "vmmdevTestingMmioRead");
AssertRCReturn(rc, rc);
+ if (pThis->fRZEnabled)
+ {
+ rc = PDMDevHlpMMIORegisterR0(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE, NIL_RTR0PTR /*pvUser*/,
+ "vmmdevTestingMmioWrite", "vmmdevTestingMmioRead");
+ AssertRCReturn(rc, rc);
+ rc = PDMDevHlpMMIORegisterRC(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE, NIL_RTRCPTR /*pvUser*/,
+ "vmmdevTestingMmioWrite", "vmmdevTestingMmioRead");
+ AssertRCReturn(rc, rc);
+ }
}
@@ -494,6 +550,14 @@ int vmmdevTestingInitialize(PPDMDEVINS pDevIns)
AssertRCReturn(rc, rc);
}
+ /*
+ * Open the XML output file(/pipe/whatever) if specfied.
+ */
+ rc = RTTestCreateEx("VMMDevTesting", RTTEST_C_USE_ENV | RTTEST_C_NO_TLS | RTTEST_C_XML_DELAY_TOP_TEST,
+ RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, pThis->pszTestingXmlOutput, &pThis->hTestingTest);
+ if (RT_FAILURE(rc))
+ return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, "Error creating testing instance");
+
return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/VMMDev/VMMDevTesting.h b/src/VBox/Devices/VMMDev/VMMDevTesting.h
index aa8f28de..c77db23b 100644
--- a/src/VBox/Devices/VMMDev/VMMDevTesting.h
+++ b/src/VBox/Devices/VMMDev/VMMDevTesting.h
@@ -24,7 +24,8 @@
RT_C_DECLS_BEGIN
-int vmmdevTestingInitialize(PPDMDEVINS pDevIns);
+int vmmdevTestingInitialize(PPDMDEVINS pDevIns);
+void vmmdevTestingTerminate(PPDMDEVINS pDevIns);
RT_C_DECLS_END