diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
|---|---|---|
| committer | <> | 2014-05-08 15:03:54 +0000 |
| commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
| tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Devices/VMMDev | |
| parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
| download | VirtualBox-master.tar.gz | |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Devices/VMMDev')
| -rw-r--r-- | src/VBox/Devices/VMMDev/VMMDev.cpp | 4122 | ||||
| -rw-r--r-- | src/VBox/Devices/VMMDev/VMMDevHGCM.cpp | 465 | ||||
| -rw-r--r-- | src/VBox/Devices/VMMDev/VMMDevHGCM.h | 2 | ||||
| -rw-r--r-- | src/VBox/Devices/VMMDev/VMMDevState.h | 72 | ||||
| -rw-r--r-- | src/VBox/Devices/VMMDev/VMMDevTesting.cpp | 152 | ||||
| -rw-r--r-- | src/VBox/Devices/VMMDev/VMMDevTesting.h | 3 |
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 |
