jasonbin

VirtualBox-5.1.16 VMMDev source

Mar 11th, 2017
307
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 167.18 KB | None | 0 0
  1. /* $Id: VMMDev.cpp $ */
  2. /** @file
  3.  * VMMDev - Guest <-> VMM/Host communication device.
  4.  */
  5.  
  6. /*
  7.  * Copyright (C) 2006-2016 Oracle Corporation
  8.  *
  9.  * This file is part of VirtualBox Open Source Edition (OSE), as
  10.  * available from http://www.virtualbox.org. This file is free software;
  11.  * you can redistribute it and/or modify it under the terms of the GNU
  12.  * General Public License (GPL) as published by the Free Software
  13.  * Foundation, in version 2 as it comes in the "COPYING" file of the
  14.  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
  15.  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  16.  */
  17.  
  18. /** @page pg_vmmdev   The VMM Device.
  19.  *
  20.  * The VMM device is a custom hardware device emulation for communicating with
  21.  * the guest additions.
  22.  *
  23.  * Whenever host wants to inform guest about something an IRQ notification will
  24.  * be raised.
  25.  *
  26.  * VMMDev PDM interface will contain the guest notification method.
  27.  *
  28.  * There is a 32 bit event mask which will be read by guest on an interrupt.  A
  29.  * non zero bit in the mask means that the specific event occurred and requires
  30.  * processing on guest side.
  31.  *
  32.  * After reading the event mask guest must issue a generic request
  33.  * AcknowlegdeEvents.
  34.  *
  35.  * IRQ line is set to 1 (request) if there are unprocessed events, that is the
  36.  * event mask is not zero.
  37.  *
  38.  * After receiving an interrupt and checking event mask, the guest must process
  39.  * events using the event specific mechanism.
  40.  *
  41.  * That is if mouse capabilities were changed, guest will use
  42.  * VMMDev_GetMouseStatus generic request.
  43.  *
  44.  * Event mask is only a set of flags indicating that guest must proceed with a
  45.  * procedure.
  46.  *
  47.  * Unsupported events are therefore ignored. The guest additions must inform
  48.  * host which events they want to receive, to avoid unnecessary IRQ processing.
  49.  * By default no events are signalled to guest.
  50.  *
  51.  * This seems to be fast method. It requires only one context switch for an
  52.  * event processing.
  53.  *
  54.  *
  55.  * @section sec_vmmdev_heartbeat    Heartbeat
  56.  *
  57.  * The heartbeat is a feature to monitor whether the guest OS is hung or not.
  58.  *
  59.  * The main kernel component of the guest additions, VBoxGuest, sets up a timer
  60.  * at a frequency returned by VMMDevReq_HeartbeatConfigure
  61.  * (VMMDevReqHeartbeat::cNsInterval, VMMDEV::cNsHeartbeatInterval) and performs
  62.  * a VMMDevReq_GuestHeartbeat request every time the timer ticks.
  63.  *
  64.  * The host side (VMMDev) arms a timer with a more distant deadline
  65.  * (VMMDEV::cNsHeartbeatTimeout), twice cNsHeartbeatInterval by default.  Each
  66.  * time a VMMDevReq_GuestHeartbeat request comes in, the timer is rearmed with
  67.  * the same relative deadline.  So, as long as VMMDevReq_GuestHeartbeat comes
  68.  * when they should, the host timer will never fire.
  69.  *
  70.  * When the timer fires, we consider the guest as hung / flatlined / dead.
  71.  * Currently we only LogRel that, but it's easy to extend this with an event in
  72.  * Main API.
  73.  *
  74.  * Should the guest reawaken at some later point, we LogRel that event and
  75.  * continue as normal.  Again something which would merit an API event.
  76.  *
  77.  */
  78.  
  79.  
  80. /*********************************************************************************************************************************
  81. *   Header Files                                                                                                                 *
  82. *********************************************************************************************************************************/
  83. /* Enable dev_vmm Log3 statements to get IRQ-related logging. */
  84. #define LOG_GROUP LOG_GROUP_DEV_VMM
  85. #include <VBox/VMMDev.h>
  86. #include <VBox/vmm/mm.h>
  87. #include <VBox/log.h>
  88. #include <VBox/param.h>
  89. #include <iprt/path.h>
  90. #include <iprt/dir.h>
  91. #include <iprt/file.h>
  92. #include <VBox/vmm/pgm.h>
  93. #include <VBox/err.h>
  94. #include <VBox/vmm/vm.h> /* for VM_IS_EMT */
  95. #include <VBox/dbg.h>
  96. #include <VBox/version.h>
  97.  
  98. #include <iprt/asm.h>
  99. #include <iprt/asm-amd64-x86.h>
  100. #include <iprt/assert.h>
  101. #include <iprt/buildconfig.h>
  102. #include <iprt/string.h>
  103. #include <iprt/time.h>
  104. #ifndef IN_RC
  105. # include <iprt/mem.h>
  106. #endif
  107. #ifdef IN_RING3
  108. # include <iprt/uuid.h>
  109. #endif
  110.  
  111. #include "VMMDevState.h"
  112. #ifdef VBOX_WITH_HGCM
  113. # include "VMMDevHGCM.h"
  114. #endif
  115. #ifndef VBOX_WITHOUT_TESTING_FEATURES
  116. # include "VMMDevTesting.h"
  117. #endif
  118.  
  119.  
  120. /*********************************************************************************************************************************
  121. *   Defined Constants And Macros                                                                                                 *
  122. *********************************************************************************************************************************/
  123. #define VMMDEV_INTERFACE_VERSION_IS_1_03(s) \
  124.     (   RT_HIWORD((s)->guestInfo.interfaceVersion) == 1 \
  125.      && RT_LOWORD((s)->guestInfo.interfaceVersion) == 3 )
  126.  
  127. #define VMMDEV_INTERFACE_VERSION_IS_OK(additionsVersion) \
  128.       (   RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
  129.        && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) )
  130.  
  131. #define VMMDEV_INTERFACE_VERSION_IS_OLD(additionsVersion) \
  132.       (   (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
  133.        || (   RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
  134.            && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) ) )
  135.  
  136. #define VMMDEV_INTERFACE_VERSION_IS_TOO_OLD(additionsVersion) \
  137.       ( RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) )
  138.  
  139. #define VMMDEV_INTERFACE_VERSION_IS_NEW(additionsVersion) \
  140.       (   RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
  141.        || (   RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
  142.            && RT_LOWORD(additionsVersion) >  RT_LOWORD(VMMDEV_VERSION) ) )
  143.  
  144. /** The saved state version. */
  145. #define VMMDEV_SAVED_STATE_VERSION                              VMMDEV_SAVED_STATE_VERSION_HEARTBEAT
  146. /** The saved state version with heartbeat state. */
  147. #define VMMDEV_SAVED_STATE_VERSION_HEARTBEAT                    16
  148. /** The saved state version without heartbeat state. */
  149. #define VMMDEV_SAVED_STATE_VERSION_NO_HEARTBEAT                 15
  150. /** The saved state version which is missing the guest facility statuses. */
  151. #define VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES    14
  152. /** The saved state version which is missing the guestInfo2 bits. */
  153. #define VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2         13
  154. /** The saved state version used by VirtualBox 3.0.
  155.  *  This doesn't have the config part. */
  156. #define VMMDEV_SAVED_STATE_VERSION_VBOX_30                      11
  157. /** Default interval in nanoseconds between guest heartbeats.
  158.  *  Used when no HeartbeatInterval is set in CFGM and for setting
  159.  *  HB check timer if the guest's heartbeat frequency is less than 1Hz. */
  160. #define VMMDEV_HEARTBEAT_DEFAULT_INTERVAL                       (2U*RT_NS_1SEC_64)
  161.  
  162.  
  163. #ifndef VBOX_DEVICE_STRUCT_TESTCASE
  164.  
  165. /* -=-=-=-=- Misc Helpers -=-=-=-=- */
  166.  
  167. /**
  168.  * Log information about the Guest Additions.
  169.  *
  170.  * @param   pGuestInfo  The information we've got from the Guest Additions driver.
  171.  */
  172. static void vmmdevLogGuestOsInfo(VBoxGuestInfo *pGuestInfo)
  173. {
  174.     const char *pszOs;
  175.     switch (pGuestInfo->osType & ~VBOXOSTYPE_x64)
  176.     {
  177.         case VBOXOSTYPE_DOS:                              pszOs = "DOS";            break;
  178.         case VBOXOSTYPE_Win31:                            pszOs = "Windows 3.1";    break;
  179.         case VBOXOSTYPE_Win9x:                            pszOs = "Windows 9x";     break;
  180.         case VBOXOSTYPE_Win95:                            pszOs = "Windows 95";     break;
  181.         case VBOXOSTYPE_Win98:                            pszOs = "Windows 98";     break;
  182.         case VBOXOSTYPE_WinMe:                            pszOs = "Windows Me";     break;
  183.         case VBOXOSTYPE_WinNT:                            pszOs = "Windows NT";     break;
  184.         case VBOXOSTYPE_WinNT4:                           pszOs = "Windows NT4";    break;
  185.         case VBOXOSTYPE_Win2k:                            pszOs = "Windows 2k";     break;
  186.         case VBOXOSTYPE_WinXP:                            pszOs = "Windows XP";     break;
  187.         case VBOXOSTYPE_Win2k3:                           pszOs = "Windows 2k3";    break;
  188.         case VBOXOSTYPE_WinVista:                         pszOs = "Windows Vista";  break;
  189.         case VBOXOSTYPE_Win2k8:                           pszOs = "Windows 2k8";    break;
  190.         case VBOXOSTYPE_Win7:                             pszOs = "Windows 7";      break;
  191.         case VBOXOSTYPE_Win8:                             pszOs = "Windows 8";      break;
  192.         case VBOXOSTYPE_Win2k12_x64 & ~VBOXOSTYPE_x64:    pszOs = "Windows 2k12";   break;
  193.         case VBOXOSTYPE_Win81:                            pszOs = "Windows 8.1";    break;
  194.         case VBOXOSTYPE_Win10:                            pszOs = "Windows 10";     break;
  195.         case VBOXOSTYPE_OS2:                              pszOs = "OS/2";           break;
  196.         case VBOXOSTYPE_OS2Warp3:                         pszOs = "OS/2 Warp 3";    break;
  197.         case VBOXOSTYPE_OS2Warp4:                         pszOs = "OS/2 Warp 4";    break;
  198.         case VBOXOSTYPE_OS2Warp45:                        pszOs = "OS/2 Warp 4.5";  break;
  199.         case VBOXOSTYPE_ECS:                              pszOs = "OS/2 ECS";       break;
  200.         case VBOXOSTYPE_OS21x:                            pszOs = "OS/2 2.1x";      break;
  201.         case VBOXOSTYPE_Linux:                            pszOs = "Linux";          break;
  202.         case VBOXOSTYPE_Linux22:                          pszOs = "Linux 2.2";      break;
  203.         case VBOXOSTYPE_Linux24:                          pszOs = "Linux 2.4";      break;
  204.         case VBOXOSTYPE_Linux26:                          pszOs = "Linux >= 2.6";   break;
  205.         case VBOXOSTYPE_ArchLinux:                        pszOs = "ArchLinux";      break;
  206.         case VBOXOSTYPE_Debian:                           pszOs = "Debian";         break;
  207.         case VBOXOSTYPE_OpenSUSE:                         pszOs = "openSUSE";       break;
  208.         case VBOXOSTYPE_FedoraCore:                       pszOs = "Fedora";         break;
  209.         case VBOXOSTYPE_Gentoo:                           pszOs = "Gentoo";         break;
  210.         case VBOXOSTYPE_Mandriva:                         pszOs = "Mandriva";       break;
  211.         case VBOXOSTYPE_RedHat:                           pszOs = "RedHat";         break;
  212.         case VBOXOSTYPE_Turbolinux:                       pszOs = "TurboLinux";     break;
  213.         case VBOXOSTYPE_Ubuntu:                           pszOs = "Ubuntu";         break;
  214.         case VBOXOSTYPE_Xandros:                          pszOs = "Xandros";        break;
  215.         case VBOXOSTYPE_Oracle:                           pszOs = "Oracle Linux";   break;
  216.         case VBOXOSTYPE_FreeBSD:                          pszOs = "FreeBSD";        break;
  217.         case VBOXOSTYPE_OpenBSD:                          pszOs = "OpenBSD";        break;
  218.         case VBOXOSTYPE_NetBSD:                           pszOs = "NetBSD";         break;
  219.         case VBOXOSTYPE_Netware:                          pszOs = "Netware";        break;
  220.         case VBOXOSTYPE_Solaris:                          pszOs = "Solaris";        break;
  221.         case VBOXOSTYPE_OpenSolaris:                      pszOs = "OpenSolaris";    break;
  222.         case VBOXOSTYPE_Solaris11_x64 & ~VBOXOSTYPE_x64:  pszOs = "Solaris 11";     break;
  223.         case VBOXOSTYPE_MacOS:                            pszOs = "Mac OS X";       break;
  224.         case VBOXOSTYPE_MacOS106:                         pszOs = "Mac OS X 10.6";  break;
  225.         case VBOXOSTYPE_MacOS107_x64 & ~VBOXOSTYPE_x64:   pszOs = "Mac OS X 10.7";  break;
  226.         case VBOXOSTYPE_MacOS108_x64 & ~VBOXOSTYPE_x64:   pszOs = "Mac OS X 10.8";  break;
  227.         case VBOXOSTYPE_MacOS109_x64 & ~VBOXOSTYPE_x64:   pszOs = "Mac OS X 10.9";  break;
  228.         case VBOXOSTYPE_MacOS1010_x64 & ~VBOXOSTYPE_x64:  pszOs = "Mac OS X 10.10"; break;
  229.         case VBOXOSTYPE_MacOS1011_x64 & ~VBOXOSTYPE_x64:  pszOs = "Mac OS X 10.11"; break;
  230.         case VBOXOSTYPE_Haiku:                            pszOs = "Haiku";          break;
  231.         default:                                          pszOs = "unknown";        break;
  232.     }
  233.     LogRel(("VMMDev: Guest Additions information report: Interface = 0x%08X osType = 0x%08X (%s, %u-bit)\n",
  234.             pGuestInfo->interfaceVersion, pGuestInfo->osType, pszOs,
  235.             pGuestInfo->osType & VBOXOSTYPE_x64 ? 64 : 32));
  236. }
  237.  
  238. /**
  239.  * Sets the IRQ (raise it or lower it) for 1.03 additions.
  240.  *
  241.  * @param   pThis       The VMMDev state.
  242.  * @thread  Any.
  243.  * @remarks Must be called owning the critical section.
  244.  */
  245. static void vmmdevSetIRQ_Legacy(PVMMDEV pThis)
  246. {
  247.     if (pThis->fu32AdditionsOk)
  248.     {
  249.         /* Filter unsupported events */
  250.         uint32_t fEvents = pThis->u32HostEventFlags & pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask;
  251.  
  252.         Log(("vmmdevSetIRQ: fEvents=%#010x, u32HostEventFlags=%#010x, u32GuestEventMask=%#010x.\n",
  253.              fEvents, pThis->u32HostEventFlags, pThis->pVMMDevRAMR3->V.V1_03.u32GuestEventMask));
  254.  
  255.         /* Move event flags to VMMDev RAM */
  256.         pThis->pVMMDevRAMR3->V.V1_03.u32HostEvents = fEvents;
  257.  
  258.         uint32_t uIRQLevel = 0;
  259.         if (fEvents)
  260.         {
  261.             /* Clear host flags which will be delivered to guest. */
  262.             pThis->u32HostEventFlags &= ~fEvents;
  263.             Log(("vmmdevSetIRQ: u32HostEventFlags=%#010x\n", pThis->u32HostEventFlags));
  264.             uIRQLevel = 1;
  265.         }
  266.  
  267.         /* Set IRQ level for pin 0 (see NoWait comment in vmmdevMaybeSetIRQ). */
  268.         /** @todo make IRQ pin configurable, at least a symbolic constant */
  269.         PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, uIRQLevel);
  270.         Log(("vmmdevSetIRQ: IRQ set %d\n", uIRQLevel));
  271.     }
  272.     else
  273.         Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
  274. }
  275.  
  276. /**
  277.  * Sets the IRQ if there are events to be delivered.
  278.  *
  279.  * @param   pThis       The VMMDev state.
  280.  * @thread  Any.
  281.  * @remarks Must be called owning the critical section.
  282.  */
  283. static void vmmdevMaybeSetIRQ(PVMMDEV pThis)
  284. {
  285.     Log3(("vmmdevMaybeSetIRQ: u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
  286.           pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
  287.  
  288.     if (pThis->u32HostEventFlags & pThis->u32GuestFilterMask)
  289.     {
  290.         /*
  291.          * Note! No need to wait for the IRQs to be set (if we're not luck
  292.          *       with the locks, etc).  It is a notification about something,
  293.          *       which has already happened.
  294.          */
  295.         pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = true;
  296.         PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 1);
  297.         Log3(("vmmdevMaybeSetIRQ: IRQ set.\n"));
  298.     }
  299. }
  300.  
  301. /**
  302.  * Notifies the guest about new events (@a fAddEvents).
  303.  *
  304.  * @param   pThis           The VMMDev state.
  305.  * @param   fAddEvents      New events to add.
  306.  * @thread  Any.
  307.  * @remarks Must be called owning the critical section.
  308.  */
  309. static void vmmdevNotifyGuestWorker(PVMMDEV pThis, uint32_t fAddEvents)
  310. {
  311.     Log3(("vmmdevNotifyGuestWorker: fAddEvents=%#010x.\n", fAddEvents));
  312.     Assert(PDMCritSectIsOwner(&pThis->CritSect));
  313.  
  314.     if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
  315.     {
  316.         Log3(("vmmdevNotifyGuestWorker: New additions detected.\n"));
  317.  
  318.         if (pThis->fu32AdditionsOk)
  319.         {
  320.             const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
  321.  
  322.             Log3(("vmmdevNotifyGuestWorker: fHadEvents=%d, u32HostEventFlags=%#010x, u32GuestFilterMask=%#010x.\n",
  323.                   fHadEvents, pThis->u32HostEventFlags, pThis->u32GuestFilterMask));
  324.  
  325.             pThis->u32HostEventFlags |= fAddEvents;
  326.  
  327.             if (!fHadEvents)
  328.                 vmmdevMaybeSetIRQ(pThis);
  329.         }
  330.         else
  331.         {
  332.             pThis->u32HostEventFlags |= fAddEvents;
  333.             Log(("vmmdevNotifyGuestWorker: IRQ is not generated, guest has not yet reported to us.\n"));
  334.         }
  335.     }
  336.     else
  337.     {
  338.         Log3(("vmmdevNotifyGuestWorker: Old additions detected.\n"));
  339.  
  340.         pThis->u32HostEventFlags |= fAddEvents;
  341.         vmmdevSetIRQ_Legacy(pThis);
  342.     }
  343. }
  344.  
  345.  
  346.  
  347. /* -=-=-=-=- Interfaces shared with VMMDevHGCM.cpp  -=-=-=-=- */
  348.  
  349. /**
  350.  * Notifies the guest about new events (@a fAddEvents).
  351.  *
  352.  * This is used by VMMDev.cpp as well as VMMDevHGCM.cpp.
  353.  *
  354.  * @param   pThis           The VMMDev state.
  355.  * @param   fAddEvents      New events to add.
  356.  * @thread  Any.
  357.  */
  358. void VMMDevNotifyGuest(PVMMDEV pThis, uint32_t fAddEvents)
  359. {
  360.     Log3(("VMMDevNotifyGuest: fAddEvents=%#010x\n", fAddEvents));
  361.  
  362.     /*
  363.      * Only notify the VM when it's running.
  364.      */
  365.     VMSTATE enmVMState = PDMDevHlpVMState(pThis->pDevIns);
  366. /** @todo r=bird: Shouldn't there be more states here?  Wouldn't we drop
  367.  *        notifications now when we're in the process of suspending or
  368.  *        similar? */
  369.     if (   enmVMState == VMSTATE_RUNNING
  370.         || enmVMState == VMSTATE_RUNNING_LS)
  371.     {
  372.         PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  373.         vmmdevNotifyGuestWorker(pThis, fAddEvents);
  374.         PDMCritSectLeave(&pThis->CritSect);
  375.     }
  376. }
  377.  
  378. /**
  379.  * Code shared by VMMDevReq_CtlGuestFilterMask and HGCM for controlling the
  380.  * events the guest are interested in.
  381.  *
  382.  * @param   pThis           The VMMDev state.
  383.  * @param   fOrMask         Events to add (VMMDEV_EVENT_XXX). Pass 0 for no
  384.  *                          change.
  385.  * @param   fNotMask        Events to remove (VMMDEV_EVENT_XXX). Pass 0 for no
  386.  *                          change.
  387.  *
  388.  * @remarks When HGCM will automatically enable VMMDEV_EVENT_HGCM when the guest
  389.  *          starts submitting HGCM requests.  Otherwise, the events are
  390.  *          controlled by the guest.
  391.  */
  392. void VMMDevCtlSetGuestFilterMask(PVMMDEV pThis, uint32_t fOrMask, uint32_t fNotMask)
  393. {
  394.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  395.  
  396.     const bool fHadEvents = (pThis->u32HostEventFlags & pThis->u32GuestFilterMask) != 0;
  397.  
  398.     Log(("VMMDevCtlSetGuestFilterMask: fOrMask=%#010x, u32NotMask=%#010x, fHadEvents=%d.\n", fOrMask, fNotMask, fHadEvents));
  399.     if (fHadEvents)
  400.     {
  401.         if (!pThis->fNewGuestFilterMask)
  402.             pThis->u32NewGuestFilterMask = pThis->u32GuestFilterMask;
  403.  
  404.         pThis->u32NewGuestFilterMask |= fOrMask;
  405.         pThis->u32NewGuestFilterMask &= ~fNotMask;
  406.         pThis->fNewGuestFilterMask = true;
  407.     }
  408.     else
  409.     {
  410.         pThis->u32GuestFilterMask |= fOrMask;
  411.         pThis->u32GuestFilterMask &= ~fNotMask;
  412.         vmmdevMaybeSetIRQ(pThis);
  413.     }
  414.  
  415.     PDMCritSectLeave(&pThis->CritSect);
  416. }
  417.  
  418.  
  419.  
  420. /* -=-=-=-=- Request processing functions. -=-=-=-=- */
  421.  
  422. /**
  423.  * Handles VMMDevReq_ReportGuestInfo.
  424.  *
  425.  * @returns VBox status code that the guest should see.
  426.  * @param   pThis           The VMMDev instance data.
  427.  * @param   pRequestHeader  The header of the request to handle.
  428.  */
  429. static int vmmdevReqHandler_ReportGuestInfo(PVMMDEV pThis, VMMDevRequestHeader *pRequestHeader)
  430. {
  431.     AssertMsgReturn(pRequestHeader->size == sizeof(VMMDevReportGuestInfo), ("%u\n", pRequestHeader->size), VERR_INVALID_PARAMETER);
  432.     VBoxGuestInfo const *pInfo = &((VMMDevReportGuestInfo *)pRequestHeader)->guestInfo;
  433.  
  434.     if (memcmp(&pThis->guestInfo, pInfo, sizeof(*pInfo)) != 0)
  435.     {
  436.         /* Make a copy of supplied information. */
  437.         pThis->guestInfo = *pInfo;
  438.  
  439.         /* Check additions interface version. */
  440.         pThis->fu32AdditionsOk = VMMDEV_INTERFACE_VERSION_IS_OK(pThis->guestInfo.interfaceVersion);
  441.  
  442.         vmmdevLogGuestOsInfo(&pThis->guestInfo);
  443.  
  444.         if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
  445.             pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
  446.     }
  447.  
  448.     if (!pThis->fu32AdditionsOk)
  449.         return VERR_VERSION_MISMATCH;
  450.  
  451.     /* Clear our IRQ in case it was high for whatever reason. */
  452.     PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
  453.  
  454.     return VINF_SUCCESS;
  455. }
  456.  
  457.  
  458. /**
  459.  * Handles VMMDevReq_GuestHeartbeat.
  460.  *
  461.  * @returns VBox status code that the guest should see.
  462.  * @param   pThis    The VMMDev instance data.
  463.  */
  464. static int vmmDevReqHandler_GuestHeartbeat(PVMMDEV pThis)
  465. {
  466.     int rc;
  467.     if (pThis->fHeartbeatActive)
  468.     {
  469.         uint64_t const nsNowTS = TMTimerGetNano(pThis->pFlatlinedTimer);
  470.         if (!pThis->fFlatlined)
  471.         { /* likely */ }
  472.         else
  473.         {
  474.             LogRel(("VMMDev: GuestHeartBeat: Guest is alive (gone %'llu ns)\n", nsNowTS - pThis->nsLastHeartbeatTS));
  475.             ASMAtomicWriteBool(&pThis->fFlatlined, false);
  476.         }
  477.         ASMAtomicWriteU64(&pThis->nsLastHeartbeatTS, nsNowTS);
  478.  
  479.         /* Postpone (or restart if we missed a beat) the timeout timer. */
  480.         rc = TMTimerSetNano(pThis->pFlatlinedTimer, pThis->cNsHeartbeatTimeout);
  481.     }
  482.     else
  483.         rc = VINF_SUCCESS;
  484.     return rc;
  485. }
  486.  
  487.  
  488. /**
  489.  * Timer that fires when where have been no heartbeats for a given time.
  490.  *
  491.  * @remarks Does not take the VMMDev critsect.
  492.  */
  493. static DECLCALLBACK(void) vmmDevHeartbeatFlatlinedTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
  494. {
  495.     RT_NOREF1(pDevIns);
  496.     PVMMDEV pThis = (PVMMDEV)pvUser;
  497.     if (pThis->fHeartbeatActive)
  498.     {
  499.         uint64_t cNsElapsed = TMTimerGetNano(pTimer) - pThis->nsLastHeartbeatTS;
  500.         if (   !pThis->fFlatlined
  501.             && cNsElapsed >= pThis->cNsHeartbeatInterval)
  502.         {
  503.             LogRel(("VMMDev: vmmDevHeartbeatFlatlinedTimer: Guest seems to be unresponsive. Last heartbeat received %RU64 seconds ago\n",
  504.                     cNsElapsed / RT_NS_1SEC));
  505.             ASMAtomicWriteBool(&pThis->fFlatlined, true);
  506.         }
  507.     }
  508. }
  509.  
  510.  
  511. /**
  512.  * Handles VMMDevReq_HeartbeatConfigure.
  513.  *
  514.  * @returns VBox status code that the guest should see.
  515.  * @param   pThis     The VMMDev instance data.
  516.  * @param   pReqHdr   The header of the request to handle.
  517.  */
  518. static int vmmDevReqHandler_HeartbeatConfigure(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  519. {
  520.     AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReqHeartbeat), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
  521.     VMMDevReqHeartbeat *pReq = (VMMDevReqHeartbeat *)pReqHdr;
  522.     int rc;
  523.  
  524.     pReq->cNsInterval = pThis->cNsHeartbeatInterval;
  525.  
  526.     if (pReq->fEnabled != pThis->fHeartbeatActive)
  527.     {
  528.         ASMAtomicWriteBool(&pThis->fHeartbeatActive, pReq->fEnabled);
  529.         if (pReq->fEnabled)
  530.         {
  531.             /*
  532.              * Activate the heartbeat monitor.
  533.              */
  534.             pThis->nsLastHeartbeatTS = TMTimerGetNano(pThis->pFlatlinedTimer);
  535.             rc = TMTimerSetNano(pThis->pFlatlinedTimer, pThis->cNsHeartbeatTimeout);
  536.             if (RT_SUCCESS(rc))
  537.                 LogRel(("VMMDev: Heartbeat flatline timer set to trigger after %'RU64 ns\n", pThis->cNsHeartbeatTimeout));
  538.             else
  539.                 LogRel(("VMMDev: Error starting flatline timer (heartbeat): %Rrc\n", rc));
  540.         }
  541.         else
  542.         {
  543.             /*
  544.              * Deactivate the heartbeat monitor.
  545.              */
  546.             rc = TMTimerStop(pThis->pFlatlinedTimer);
  547.             LogRel(("VMMDev: Heartbeat checking timer has been stopped (rc=%Rrc)\n", rc));
  548.         }
  549.     }
  550.     else
  551.     {
  552.         LogRel(("VMMDev: vmmDevReqHandler_HeartbeatConfigure: No change (fHeartbeatActive=%RTbool).\n", pThis->fHeartbeatActive));
  553.         rc = VINF_SUCCESS;
  554.     }
  555.  
  556.     return rc;
  557. }
  558.  
  559.  
  560. /**
  561.  * Validates a publisher tag.
  562.  *
  563.  * @returns true / false.
  564.  * @param   pszTag              Tag to validate.
  565.  */
  566. static bool vmmdevReqIsValidPublisherTag(const char *pszTag)
  567. {
  568.     /* Note! This character set is also found in Config.kmk. */
  569.     static char const s_szValidChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz()[]{}+-.,";
  570.  
  571.     while (*pszTag != '\0')
  572.     {
  573.         if (!strchr(s_szValidChars, *pszTag))
  574.             return false;
  575.         pszTag++;
  576.     }
  577.     return true;
  578. }
  579.  
  580.  
  581. /**
  582.  * Validates a build tag.
  583.  *
  584.  * @returns true / false.
  585.  * @param   pszTag              Tag to validate.
  586.  */
  587. static bool vmmdevReqIsValidBuildTag(const char *pszTag)
  588. {
  589.     int cchPrefix;
  590.     if (!strncmp(pszTag, "RC", 2))
  591.         cchPrefix = 2;
  592.     else if (!strncmp(pszTag, "BETA", 4))
  593.         cchPrefix = 4;
  594.     else if (!strncmp(pszTag, "ALPHA", 5))
  595.         cchPrefix = 5;
  596.     else
  597.         return false;
  598.  
  599.     if (pszTag[cchPrefix] == '\0')
  600.         return true;
  601.  
  602.     uint8_t u8;
  603.     int rc = RTStrToUInt8Full(&pszTag[cchPrefix], 10, &u8);
  604.     return rc == VINF_SUCCESS;
  605. }
  606.  
  607.  
  608. /**
  609.  * Handles VMMDevReq_ReportGuestInfo2.
  610.  *
  611.  * @returns VBox status code that the guest should see.
  612.  * @param   pThis           The VMMDev instance data.
  613.  * @param   pReqHdr         The header of the request to handle.
  614.  */
  615. static int vmmdevReqHandler_ReportGuestInfo2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  616. {
  617.     AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReportGuestInfo2), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
  618.     VBoxGuestInfo2 const *pInfo2 = &((VMMDevReportGuestInfo2 *)pReqHdr)->guestInfo;
  619.  
  620.     LogRel(("VMMDev: Guest Additions information report: Version %d.%d.%d r%d '%.*s'\n",
  621.             pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild,
  622.             pInfo2->additionsRevision, sizeof(pInfo2->szName), pInfo2->szName));
  623.  
  624.     /* The interface was introduced in 3.2 and will definitely not be
  625.        backported beyond 3.0 (bird). */
  626.     AssertMsgReturn(pInfo2->additionsMajor >= 3,
  627.                     ("%u.%u.%u\n", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild),
  628.                     VERR_INVALID_PARAMETER);
  629.  
  630.     /* The version must fit in a full version compression. */
  631.     uint32_t uFullVersion = VBOX_FULL_VERSION_MAKE(pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild);
  632.     AssertMsgReturn(   VBOX_FULL_VERSION_GET_MAJOR(uFullVersion) == pInfo2->additionsMajor
  633.                     && VBOX_FULL_VERSION_GET_MINOR(uFullVersion) == pInfo2->additionsMinor
  634.                     && VBOX_FULL_VERSION_GET_BUILD(uFullVersion) == pInfo2->additionsBuild,
  635.                     ("%u.%u.%u\n", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild),
  636.                     VERR_OUT_OF_RANGE);
  637.  
  638.     /*
  639.      * Validate the name.
  640.      * Be less strict towards older additions (< v4.1.50).
  641.      */
  642.     AssertCompile(sizeof(pThis->guestInfo2.szName) == sizeof(pInfo2->szName));
  643.     AssertReturn(RTStrEnd(pInfo2->szName, sizeof(pInfo2->szName)) != NULL, VERR_INVALID_PARAMETER);
  644.     const char *pszName = pInfo2->szName;
  645.  
  646.     /* The version number which shouldn't be there. */
  647.     char        szTmp[sizeof(pInfo2->szName)];
  648.     size_t      cchStart = RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u", pInfo2->additionsMajor, pInfo2->additionsMinor, pInfo2->additionsBuild);
  649.     AssertMsgReturn(!strncmp(pszName, szTmp, cchStart), ("%s != %s\n", pszName, szTmp), VERR_INVALID_PARAMETER);
  650.     pszName += cchStart;
  651.  
  652.     /* Now we can either have nothing or a build tag or/and a publisher tag. */
  653.     if (*pszName != '\0')
  654.     {
  655.         const char *pszRelaxedName = "";
  656.         bool const fStrict = pInfo2->additionsMajor > 4
  657.                           || (pInfo2->additionsMajor == 4 && pInfo2->additionsMinor > 1)
  658.                           || (pInfo2->additionsMajor == 4 && pInfo2->additionsMinor == 1 && pInfo2->additionsBuild >= 50);
  659.         bool fOk = false;
  660.         if (*pszName == '_')
  661.         {
  662.             pszName++;
  663.             strcpy(szTmp, pszName);
  664.             char *pszTag2 = strchr(szTmp, '_');
  665.             if (!pszTag2)
  666.             {
  667.                 fOk = vmmdevReqIsValidBuildTag(szTmp)
  668.                    || vmmdevReqIsValidPublisherTag(szTmp);
  669.             }
  670.             else
  671.             {
  672.                 *pszTag2++ = '\0';
  673.                 fOk = vmmdevReqIsValidBuildTag(szTmp);
  674.                 if (fOk)
  675.                 {
  676.                     fOk = vmmdevReqIsValidPublisherTag(pszTag2);
  677.                     if (!fOk)
  678.                         pszRelaxedName = szTmp;
  679.                 }
  680.             }
  681.         }
  682.  
  683.         if (!fOk)
  684.         {
  685.             AssertLogRelMsgReturn(!fStrict, ("%s", pszName), VERR_INVALID_PARAMETER);
  686.  
  687.             /* non-strict mode, just zap the extra stuff. */
  688.             LogRel(("VMMDev: ReportGuestInfo2: Ignoring unparsable version name bits: '%s' -> '%s'.\n", pszName, pszRelaxedName));
  689.             pszName = pszRelaxedName;
  690.         }
  691.     }
  692.  
  693.     /*
  694.      * Save the info and tell Main or whoever is listening.
  695.      */
  696.     pThis->guestInfo2.uFullVersion  = uFullVersion;
  697.     pThis->guestInfo2.uRevision     = pInfo2->additionsRevision;
  698.     pThis->guestInfo2.fFeatures     = pInfo2->additionsFeatures;
  699.     strcpy(pThis->guestInfo2.szName, pszName);
  700.  
  701.     if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo2)
  702.         pThis->pDrv->pfnUpdateGuestInfo2(pThis->pDrv, uFullVersion, pszName, pInfo2->additionsRevision, pInfo2->additionsFeatures);
  703.  
  704.     /* Clear our IRQ in case it was high for whatever reason. */
  705.     PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
  706.  
  707.     return VINF_SUCCESS;
  708. }
  709.  
  710.  
  711. /**
  712.  * Allocates a new facility status entry, initializing it to inactive.
  713.  *
  714.  * @returns Pointer to a facility status entry on success, NULL on failure
  715.  *          (table full).
  716.  * @param   pThis           The VMMDev instance data.
  717.  * @param   enmFacility     The facility type code.
  718.  * @param   fFixed          This is set when allocating the standard entries
  719.  *                          from the constructor.
  720.  * @param   pTimeSpecNow    Optionally giving the entry timestamp to use (ctor).
  721.  */
  722. static PVMMDEVFACILITYSTATUSENTRY
  723. vmmdevAllocFacilityStatusEntry(PVMMDEV pThis, VBoxGuestFacilityType enmFacility, bool fFixed, PCRTTIMESPEC pTimeSpecNow)
  724. {
  725.     /* If full, expunge one inactive entry. */
  726.     if (pThis->cFacilityStatuses == RT_ELEMENTS(pThis->aFacilityStatuses))
  727.     {
  728.         uint32_t i = pThis->cFacilityStatuses;
  729.         while (i-- > 0)
  730.         {
  731.             if (   pThis->aFacilityStatuses[i].enmStatus == VBoxGuestFacilityStatus_Inactive
  732.                 && !pThis->aFacilityStatuses[i].fFixed)
  733.             {
  734.                 pThis->cFacilityStatuses--;
  735.                 int cToMove = pThis->cFacilityStatuses - i;
  736.                 if (cToMove)
  737.                     memmove(&pThis->aFacilityStatuses[i], &pThis->aFacilityStatuses[i + 1],
  738.                             cToMove * sizeof(pThis->aFacilityStatuses[i]));
  739.                 RT_ZERO(pThis->aFacilityStatuses[pThis->cFacilityStatuses]);
  740.                 break;
  741.             }
  742.         }
  743.  
  744.         if (pThis->cFacilityStatuses == RT_ELEMENTS(pThis->aFacilityStatuses))
  745.             return NULL;
  746.     }
  747.  
  748.     /* Find location in array (it's sorted). */
  749.     uint32_t i = pThis->cFacilityStatuses;
  750.     while (i-- > 0)
  751.         if ((uint32_t)pThis->aFacilityStatuses[i].enmFacility < (uint32_t)enmFacility)
  752.             break;
  753.     i++;
  754.  
  755.     /* Move. */
  756.     int cToMove = pThis->cFacilityStatuses - i;
  757.     if (cToMove > 0)
  758.         memmove(&pThis->aFacilityStatuses[i + 1], &pThis->aFacilityStatuses[i],
  759.                 cToMove * sizeof(pThis->aFacilityStatuses[i]));
  760.     pThis->cFacilityStatuses++;
  761.  
  762.     /* Initialize. */
  763.     pThis->aFacilityStatuses[i].enmFacility  = enmFacility;
  764.     pThis->aFacilityStatuses[i].enmStatus    = VBoxGuestFacilityStatus_Inactive;
  765.     pThis->aFacilityStatuses[i].fFixed       = fFixed;
  766.     pThis->aFacilityStatuses[i].afPadding[0] = 0;
  767.     pThis->aFacilityStatuses[i].afPadding[1] = 0;
  768.     pThis->aFacilityStatuses[i].afPadding[2] = 0;
  769.     pThis->aFacilityStatuses[i].fFlags       = 0;
  770.     if (pTimeSpecNow)
  771.         pThis->aFacilityStatuses[i].TimeSpecTS = *pTimeSpecNow;
  772.     else
  773.         RTTimeSpecSetNano(&pThis->aFacilityStatuses[i].TimeSpecTS, 0);
  774.  
  775.     return &pThis->aFacilityStatuses[i];
  776. }
  777.  
  778.  
  779. /**
  780.  * Gets a facility status entry, allocating a new one if not already present.
  781.  *
  782.  * @returns Pointer to a facility status entry on success, NULL on failure
  783.  *          (table full).
  784.  * @param   pThis           The VMMDev instance data.
  785.  * @param   enmFacility     The facility type code.
  786.  */
  787. static PVMMDEVFACILITYSTATUSENTRY vmmdevGetFacilityStatusEntry(PVMMDEV pThis, VBoxGuestFacilityType enmFacility)
  788. {
  789.     /** @todo change to binary search. */
  790.     uint32_t i = pThis->cFacilityStatuses;
  791.     while (i-- > 0)
  792.     {
  793.         if (pThis->aFacilityStatuses[i].enmFacility == enmFacility)
  794.             return &pThis->aFacilityStatuses[i];
  795.         if ((uint32_t)pThis->aFacilityStatuses[i].enmFacility < (uint32_t)enmFacility)
  796.             break;
  797.     }
  798.     return vmmdevAllocFacilityStatusEntry(pThis, enmFacility, false /*fFixed*/, NULL);
  799. }
  800.  
  801.  
  802. /**
  803.  * Handles VMMDevReq_ReportGuestStatus.
  804.  *
  805.  * @returns VBox status code that the guest should see.
  806.  * @param   pThis           The VMMDev instance data.
  807.  * @param   pReqHdr         The header of the request to handle.
  808.  */
  809. static int vmmdevReqHandler_ReportGuestStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  810. {
  811.     /*
  812.      * Validate input.
  813.      */
  814.     AssertMsgReturn(pReqHdr->size == sizeof(VMMDevReportGuestStatus), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
  815.     VBoxGuestStatus *pStatus = &((VMMDevReportGuestStatus *)pReqHdr)->guestStatus;
  816.     AssertMsgReturn(   pStatus->facility > VBoxGuestFacilityType_Unknown
  817.                     && pStatus->facility <= VBoxGuestFacilityType_All,
  818.                     ("%d\n", pStatus->facility),
  819.                     VERR_INVALID_PARAMETER);
  820.     AssertMsgReturn(pStatus->status == (VBoxGuestFacilityStatus)(uint16_t)pStatus->status,
  821.                     ("%#x (%u)\n", pStatus->status, pStatus->status),
  822.                     VERR_OUT_OF_RANGE);
  823.  
  824.     /*
  825.      * Do the update.
  826.      */
  827.     RTTIMESPEC Now;
  828.     RTTimeNow(&Now);
  829.     if (pStatus->facility == VBoxGuestFacilityType_All)
  830.     {
  831.         uint32_t i = pThis->cFacilityStatuses;
  832.         while (i-- > 0)
  833.         {
  834.             pThis->aFacilityStatuses[i].TimeSpecTS = Now;
  835.             pThis->aFacilityStatuses[i].enmStatus  = pStatus->status;
  836.             pThis->aFacilityStatuses[i].fFlags     = pStatus->flags;
  837.         }
  838.     }
  839.     else
  840.     {
  841.         PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, pStatus->facility);
  842.         if (!pEntry)
  843.         {
  844.             LogRelMax(10, ("VMMDev: Facility table is full - facility=%u status=%u\n", pStatus->facility, pStatus->status));
  845.             return VERR_OUT_OF_RESOURCES;
  846.         }
  847.  
  848.         pEntry->TimeSpecTS = Now;
  849.         pEntry->enmStatus  = pStatus->status;
  850.         pEntry->fFlags     = pStatus->flags;
  851.     }
  852.  
  853.     if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestStatus)
  854.         pThis->pDrv->pfnUpdateGuestStatus(pThis->pDrv, pStatus->facility, pStatus->status, pStatus->flags, &Now);
  855.  
  856.     return VINF_SUCCESS;
  857. }
  858.  
  859.  
  860. /**
  861.  * Handles VMMDevReq_ReportGuestUserState.
  862.  *
  863.  * @returns VBox status code that the guest should see.
  864.  * @param   pThis           The VMMDev instance data.
  865.  * @param   pReqHdr         The header of the request to handle.
  866.  */
  867. static int vmmdevReqHandler_ReportGuestUserState(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  868. {
  869.     /*
  870.      * Validate input.
  871.      */
  872.     VMMDevReportGuestUserState *pReq = (VMMDevReportGuestUserState *)pReqHdr;
  873.     AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
  874.  
  875.     if (   pThis->pDrv
  876.         && pThis->pDrv->pfnUpdateGuestUserState)
  877.     {
  878.         /* Play safe. */
  879.         AssertReturn(pReq->header.size      <= _2K, VERR_TOO_MUCH_DATA);
  880.         AssertReturn(pReq->status.cbUser    <= 256, VERR_TOO_MUCH_DATA);
  881.         AssertReturn(pReq->status.cbDomain  <= 256, VERR_TOO_MUCH_DATA);
  882.         AssertReturn(pReq->status.cbDetails <= _1K, VERR_TOO_MUCH_DATA);
  883.  
  884.         /* pbDynamic marks the beginning of the struct's dynamically
  885.          * allocated data area. */
  886.         uint8_t *pbDynamic = (uint8_t *)&pReq->status.szUser;
  887.         uint32_t cbLeft    = pReqHdr->size - RT_OFFSETOF(VMMDevReportGuestUserState, status.szUser);
  888.  
  889.         /* The user. */
  890.         AssertReturn(pReq->status.cbUser > 0, VERR_INVALID_PARAMETER); /* User name is required. */
  891.         AssertReturn(pReq->status.cbUser <= cbLeft, VERR_INVALID_PARAMETER);
  892.         const char *pszUser = (const char *)pbDynamic;
  893.         AssertReturn(RTStrEnd(pszUser, pReq->status.cbUser), VERR_INVALID_PARAMETER);
  894.         int rc = RTStrValidateEncoding(pszUser);
  895.         AssertRCReturn(rc, rc);
  896.  
  897.         /* Advance to the next field. */
  898.         pbDynamic += pReq->status.cbUser;
  899.         cbLeft    -= pReq->status.cbUser;
  900.  
  901.         /* pszDomain can be NULL. */
  902.         AssertReturn(pReq->status.cbDomain <= cbLeft, VERR_INVALID_PARAMETER);
  903.         const char *pszDomain = NULL;
  904.         if (pReq->status.cbDomain)
  905.         {
  906.             pszDomain = (const char *)pbDynamic;
  907.             AssertReturn(RTStrEnd(pszDomain, pReq->status.cbDomain), VERR_INVALID_PARAMETER);
  908.             rc = RTStrValidateEncoding(pszDomain);
  909.             AssertRCReturn(rc, rc);
  910.  
  911.             /* Advance to the next field. */
  912.             pbDynamic += pReq->status.cbDomain;
  913.             cbLeft    -= pReq->status.cbDomain;
  914.         }
  915.  
  916.         /* pbDetails can be NULL. */
  917.         const uint8_t *pbDetails = NULL;
  918.         AssertReturn(pReq->status.cbDetails <= cbLeft, VERR_INVALID_PARAMETER);
  919.         if (pReq->status.cbDetails > 0)
  920.             pbDetails = pbDynamic;
  921.  
  922.         pThis->pDrv->pfnUpdateGuestUserState(pThis->pDrv, pszUser, pszDomain, (uint32_t)pReq->status.state,
  923.                                              pbDetails, pReq->status.cbDetails);
  924.     }
  925.  
  926.     return VINF_SUCCESS;
  927. }
  928.  
  929.  
  930. /**
  931.  * Handles VMMDevReq_ReportGuestCapabilities.
  932.  *
  933.  * @returns VBox status code that the guest should see.
  934.  * @param   pThis           The VMMDev instance data.
  935.  * @param   pReqHdr         The header of the request to handle.
  936.  */
  937. static int vmmdevReqHandler_ReportGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  938. {
  939.     VMMDevReqGuestCapabilities *pReq = (VMMDevReqGuestCapabilities *)pReqHdr;
  940.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  941.  
  942.     /* Enable VMMDEV_GUEST_SUPPORTS_GRAPHICS automatically for guests using the old
  943.      * request to report their capabilities.
  944.      */
  945.     const uint32_t fu32Caps = pReq->caps | VMMDEV_GUEST_SUPPORTS_GRAPHICS;
  946.  
  947.     if (pThis->guestCaps != fu32Caps)
  948.     {
  949.         /* make a copy of supplied information */
  950.         pThis->guestCaps = fu32Caps;
  951.  
  952.         LogRel(("VMMDev: Guest Additions capability report (legacy): (0x%x) seamless: %s, hostWindowMapping: %s, graphics: yes\n",
  953.                 fu32Caps,
  954.                 fu32Caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
  955.                 fu32Caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no"));
  956.  
  957.         if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
  958.             pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, fu32Caps);
  959.     }
  960.     return VINF_SUCCESS;
  961. }
  962.  
  963.  
  964. /**
  965.  * Handles VMMDevReq_SetGuestCapabilities.
  966.  *
  967.  * @returns VBox status code that the guest should see.
  968.  * @param   pThis           The VMMDev instance data.
  969.  * @param   pReqHdr         The header of the request to handle.
  970.  */
  971. static int vmmdevReqHandler_SetGuestCapabilities(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  972. {
  973.     VMMDevReqGuestCapabilities2 *pReq = (VMMDevReqGuestCapabilities2 *)pReqHdr;
  974.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  975.  
  976.     uint32_t fu32Caps = pThis->guestCaps;
  977.     fu32Caps |= pReq->u32OrMask;
  978.     fu32Caps &= ~pReq->u32NotMask;
  979.  
  980.     LogRel(("VMMDev: Guest Additions capability report: (%#x -> %#x) seamless: %s, hostWindowMapping: %s, graphics: %s\n",
  981.             pThis->guestCaps, fu32Caps,
  982.             fu32Caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
  983.             fu32Caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
  984.             fu32Caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
  985.  
  986.     pThis->guestCaps = fu32Caps;
  987.  
  988.     if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
  989.         pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, fu32Caps);
  990.  
  991.     return VINF_SUCCESS;
  992. }
  993.  
  994.  
  995. /**
  996.  * Handles VMMDevReq_GetMouseStatus.
  997.  *
  998.  * @returns VBox status code that the guest should see.
  999.  * @param   pThis           The VMMDev instance data.
  1000.  * @param   pReqHdr         The header of the request to handle.
  1001.  */
  1002. static int vmmdevReqHandler_GetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1003. {
  1004.     VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
  1005.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1006.  
  1007.     pReq->mouseFeatures = pThis->mouseCapabilities
  1008.                         & VMMDEV_MOUSE_MASK;
  1009.     pReq->pointerXPos   = pThis->mouseXAbs;
  1010.     pReq->pointerYPos   = pThis->mouseYAbs;
  1011.     LogRel2(("VMMDev: vmmdevReqHandler_GetMouseStatus: mouseFeatures=%#x, xAbs=%d, yAbs=%d\n",
  1012.              pReq->mouseFeatures, pReq->pointerXPos, pReq->pointerYPos));
  1013.     return VINF_SUCCESS;
  1014. }
  1015.  
  1016.  
  1017. /**
  1018.  * Handles VMMDevReq_SetMouseStatus.
  1019.  *
  1020.  * @returns VBox status code that the guest should see.
  1021.  * @param   pThis           The VMMDev instance data.
  1022.  * @param   pReqHdr         The header of the request to handle.
  1023.  */
  1024. static int vmmdevReqHandler_SetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1025. {
  1026.     VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
  1027.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1028.  
  1029.     LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: mouseFeatures=%#x\n", pReq->mouseFeatures));
  1030.  
  1031.     bool fNotify = false;
  1032.     if (   (pReq->mouseFeatures & VMMDEV_MOUSE_NOTIFY_HOST_MASK)
  1033.         != (  pThis->mouseCapabilities
  1034.             & VMMDEV_MOUSE_NOTIFY_HOST_MASK))
  1035.         fNotify = true;
  1036.  
  1037.     pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
  1038.     pThis->mouseCapabilities |= (pReq->mouseFeatures & VMMDEV_MOUSE_GUEST_MASK);
  1039.  
  1040.     LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: New host capabilities: %#x\n", pThis->mouseCapabilities));
  1041.  
  1042.     /*
  1043.      * Notify connector if something changed.
  1044.      */
  1045.     if (fNotify)
  1046.     {
  1047.         LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: Notifying connector\n"));
  1048.         pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
  1049.     }
  1050.  
  1051.     return VINF_SUCCESS;
  1052. }
  1053.  
  1054. static int vmmdevVerifyPointerShape(VMMDevReqMousePointer *pReq)
  1055. {
  1056.     /* Should be enough for most mouse pointers. */
  1057.     if (pReq->width > 8192 || pReq->height > 8192)
  1058.         return VERR_INVALID_PARAMETER;
  1059.  
  1060.     uint32_t cbShape = (pReq->width + 7) / 8 * pReq->height; /* size of the AND mask */
  1061.     cbShape = ((cbShape + 3) & ~3) + pReq->width * 4 * pReq->height; /* + gap + size of the XOR mask */
  1062.     if (RT_UOFFSETOF(VMMDevReqMousePointer, pointerData) + cbShape > pReq->header.size)
  1063.         return VERR_INVALID_PARAMETER;
  1064.  
  1065.     return VINF_SUCCESS;
  1066. }
  1067.  
  1068. /**
  1069.  * Handles VMMDevReq_SetPointerShape.
  1070.  *
  1071.  * @returns VBox status code that the guest should see.
  1072.  * @param   pThis           The VMMDev instance data.
  1073.  * @param   pReqHdr         The header of the request to handle.
  1074.  */
  1075. static int vmmdevReqHandler_SetPointerShape(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1076. {
  1077.     VMMDevReqMousePointer *pReq = (VMMDevReqMousePointer *)pReqHdr;
  1078.     if (pReq->header.size < sizeof(*pReq))
  1079.     {
  1080.         AssertMsg(pReq->header.size == 0x10028 && pReq->header.version == 10000,  /* don't complain about legacy!!! */
  1081.                   ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
  1082.                    pReq->header.size, pReq->header.size, pReq->header.version));
  1083.         return VERR_INVALID_PARAMETER;
  1084.     }
  1085.  
  1086.     bool fVisible = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_VISIBLE);
  1087.     bool fAlpha   = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_ALPHA);
  1088.     bool fShape   = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_SHAPE);
  1089.  
  1090.     Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
  1091.          fVisible, fAlpha, fShape, pReq->width, pReq->height));
  1092.  
  1093.     if (pReq->header.size == sizeof(VMMDevReqMousePointer))
  1094.     {
  1095.         /* The guest did not provide the shape actually. */
  1096.         fShape = false;
  1097.     }
  1098.  
  1099.     /* forward call to driver */
  1100.     if (fShape)
  1101.     {
  1102.         int rc = vmmdevVerifyPointerShape(pReq);
  1103.         if (RT_FAILURE(rc))
  1104.             return rc;
  1105.  
  1106.         pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
  1107.                                            fVisible,
  1108.                                            fAlpha,
  1109.                                            pReq->xHot, pReq->yHot,
  1110.                                            pReq->width, pReq->height,
  1111.                                            pReq->pointerData);
  1112.     }
  1113.     else
  1114.     {
  1115.         pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
  1116.                                            fVisible,
  1117.                                            0,
  1118.                                            0, 0,
  1119.                                            0, 0,
  1120.                                            NULL);
  1121.     }
  1122.  
  1123.     pThis->fHostCursorRequested = fVisible;
  1124.     return VINF_SUCCESS;
  1125. }
  1126.  
  1127.  
  1128. /**
  1129.  * Handles VMMDevReq_GetHostTime.
  1130.  *
  1131.  * @returns VBox status code that the guest should see.
  1132.  * @param   pThis           The VMMDev instance data.
  1133.  * @param   pReqHdr         The header of the request to handle.
  1134.  */
  1135. static int vmmdevReqHandler_GetHostTime(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1136. {
  1137.     VMMDevReqHostTime *pReq = (VMMDevReqHostTime *)pReqHdr;
  1138.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1139.  
  1140.     if (RT_LIKELY(!pThis->fGetHostTimeDisabled))
  1141.     {
  1142.         RTTIMESPEC now;
  1143.         pReq->time = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pThis->pDevIns, &now));
  1144.         return VINF_SUCCESS;
  1145.     }
  1146.     return VERR_NOT_SUPPORTED;
  1147. }
  1148.  
  1149.  
  1150. /**
  1151.  * Handles VMMDevReq_GetHypervisorInfo.
  1152.  *
  1153.  * @returns VBox status code that the guest should see.
  1154.  * @param   pThis           The VMMDev instance data.
  1155.  * @param   pReqHdr         The header of the request to handle.
  1156.  */
  1157. static int vmmdevReqHandler_GetHypervisorInfo(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1158. {
  1159.     VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
  1160.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1161.  
  1162.     return PGMR3MappingsSize(PDMDevHlpGetVM(pThis->pDevIns), &pReq->hypervisorSize);
  1163. }
  1164.  
  1165.  
  1166. /**
  1167.  * Handles VMMDevReq_SetHypervisorInfo.
  1168.  *
  1169.  * @returns VBox status code that the guest should see.
  1170.  * @param   pThis           The VMMDev instance data.
  1171.  * @param   pReqHdr         The header of the request to handle.
  1172.  */
  1173. static int vmmdevReqHandler_SetHypervisorInfo(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1174. {
  1175.     VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
  1176.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1177.  
  1178.     int rc;
  1179.     PVM pVM = PDMDevHlpGetVM(pThis->pDevIns);
  1180.     if (pReq->hypervisorStart == 0)
  1181.         rc = PGMR3MappingsUnfix(pVM);
  1182.     else
  1183.     {
  1184.         /* only if the client has queried the size before! */
  1185.         uint32_t cbMappings;
  1186.         rc = PGMR3MappingsSize(pVM, &cbMappings);
  1187.         if (RT_SUCCESS(rc) && pReq->hypervisorSize == cbMappings)
  1188.         {
  1189.             /* new reservation */
  1190.             rc = PGMR3MappingsFix(pVM, pReq->hypervisorStart, pReq->hypervisorSize);
  1191.             LogRel(("VMMDev: Guest reported fixed hypervisor window at 0%010x LB %#x (rc=%Rrc)\n",
  1192.                     pReq->hypervisorStart, pReq->hypervisorSize, rc));
  1193.         }
  1194.         else if (RT_FAILURE(rc))
  1195.             rc = VERR_TRY_AGAIN;
  1196.     }
  1197.     return rc;
  1198. }
  1199.  
  1200.  
  1201. /**
  1202.  * Handles VMMDevReq_RegisterPatchMemory.
  1203.  *
  1204.  * @returns VBox status code that the guest should see.
  1205.  * @param   pThis           The VMMDev instance data.
  1206.  * @param   pReqHdr         The header of the request to handle.
  1207.  */
  1208. static int vmmdevReqHandler_RegisterPatchMemory(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1209. {
  1210.     VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
  1211.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1212.  
  1213.     return VMMR3RegisterPatchMemory(PDMDevHlpGetVM(pThis->pDevIns), pReq->pPatchMem, pReq->cbPatchMem);
  1214. }
  1215.  
  1216.  
  1217. /**
  1218.  * Handles VMMDevReq_DeregisterPatchMemory.
  1219.  *
  1220.  * @returns VBox status code that the guest should see.
  1221.  * @param   pThis           The VMMDev instance data.
  1222.  * @param   pReqHdr         The header of the request to handle.
  1223.  */
  1224. static int vmmdevReqHandler_DeregisterPatchMemory(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1225. {
  1226.     VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
  1227.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1228.  
  1229.     return VMMR3DeregisterPatchMemory(PDMDevHlpGetVM(pThis->pDevIns), pReq->pPatchMem, pReq->cbPatchMem);
  1230. }
  1231.  
  1232.  
  1233. /**
  1234.  * Handles VMMDevReq_SetPowerStatus.
  1235.  *
  1236.  * @returns VBox status code that the guest should see.
  1237.  * @param   pThis           The VMMDev instance data.
  1238.  * @param   pReqHdr         The header of the request to handle.
  1239.  */
  1240. static int vmmdevReqHandler_SetPowerStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1241. {
  1242.     VMMDevPowerStateRequest *pReq = (VMMDevPowerStateRequest *)pReqHdr;
  1243.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1244.  
  1245.     switch (pReq->powerState)
  1246.     {
  1247.         case VMMDevPowerState_Pause:
  1248.         {
  1249.             LogRel(("VMMDev: Guest requests the VM to be suspended (paused)\n"));
  1250.             return PDMDevHlpVMSuspend(pThis->pDevIns);
  1251.         }
  1252.  
  1253.         case VMMDevPowerState_PowerOff:
  1254.         {
  1255.             LogRel(("VMMDev: Guest requests the VM to be turned off\n"));
  1256.             return PDMDevHlpVMPowerOff(pThis->pDevIns);
  1257.         }
  1258.  
  1259.         case VMMDevPowerState_SaveState:
  1260.         {
  1261.             if (true /*pThis->fAllowGuestToSaveState*/)
  1262.             {
  1263.                 LogRel(("VMMDev: Guest requests the VM to be saved and powered off\n"));
  1264.                 return PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
  1265.             }
  1266.             LogRel(("VMMDev: Guest requests the VM to be saved and powered off, declined\n"));
  1267.             return VERR_ACCESS_DENIED;
  1268.         }
  1269.  
  1270.         default:
  1271.             AssertMsgFailed(("VMMDev: Invalid power state request: %d\n", pReq->powerState));
  1272.             return VERR_INVALID_PARAMETER;
  1273.     }
  1274. }
  1275.  
  1276.  
  1277. /**
  1278.  * Handles VMMDevReq_GetDisplayChangeRequest
  1279.  *
  1280.  * @returns VBox status code that the guest should see.
  1281.  * @param   pThis           The VMMDev instance data.
  1282.  * @param   pReqHdr         The header of the request to handle.
  1283.  * @remarks Deprecated.
  1284.  */
  1285. static int vmmdevReqHandler_GetDisplayChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1286. {
  1287.     VMMDevDisplayChangeRequest *pReq = (VMMDevDisplayChangeRequest *)pReqHdr;
  1288.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1289.  
  1290. /**
  1291.  * @todo It looks like a multi-monitor guest which only uses
  1292.  *        @c VMMDevReq_GetDisplayChangeRequest (not the *2 version) will get
  1293.  *        into a @c VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST event loop if it tries
  1294.  *        to acknowlege host requests for additional monitors.  Should the loop
  1295.  *        which checks for those requests be removed?
  1296.  */
  1297.  
  1298.     DISPLAYCHANGEREQUEST *pDispRequest = &pThis->displayChangeData.aRequests[0];
  1299.  
  1300.     if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
  1301.     {
  1302.         /* Current request has been read at least once. */
  1303.         pDispRequest->fPending = false;
  1304.  
  1305.         /* Check if there are more pending requests. */
  1306.         for (unsigned i = 1; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
  1307.         {
  1308.             if (pThis->displayChangeData.aRequests[i].fPending)
  1309.             {
  1310.                 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
  1311.                 break;
  1312.             }
  1313.         }
  1314.  
  1315.         /* Remember which resolution the client has queried, subsequent reads
  1316.          * will return the same values. */
  1317.         pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
  1318.         pThis->displayChangeData.fGuestSentChangeEventAck = true;
  1319.     }
  1320.  
  1321.     if (pThis->displayChangeData.fGuestSentChangeEventAck)
  1322.     {
  1323.         pReq->xres = pDispRequest->lastReadDisplayChangeRequest.xres;
  1324.         pReq->yres = pDispRequest->lastReadDisplayChangeRequest.yres;
  1325.         pReq->bpp  = pDispRequest->lastReadDisplayChangeRequest.bpp;
  1326.     }
  1327.     else
  1328.     {
  1329.         /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
  1330.          * read the last valid video mode hint. This happens when the guest X server
  1331.          * determines the initial mode. */
  1332.         pReq->xres = pDispRequest->displayChangeRequest.xres;
  1333.         pReq->yres = pDispRequest->displayChangeRequest.yres;
  1334.         pReq->bpp  = pDispRequest->displayChangeRequest.bpp;
  1335.     }
  1336.     Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n", pReq->xres, pReq->yres, pReq->bpp));
  1337.  
  1338.     return VINF_SUCCESS;
  1339. }
  1340.  
  1341.  
  1342. /**
  1343.  * Handles VMMDevReq_GetDisplayChangeRequest2.
  1344.  *
  1345.  * @returns VBox status code that the guest should see.
  1346.  * @param   pThis           The VMMDev instance data.
  1347.  * @param   pReqHdr         The header of the request to handle.
  1348.  */
  1349. static int vmmdevReqHandler_GetDisplayChangeRequest2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1350. {
  1351.     VMMDevDisplayChangeRequest2 *pReq = (VMMDevDisplayChangeRequest2 *)pReqHdr;
  1352.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1353.  
  1354.     DISPLAYCHANGEREQUEST *pDispRequest = NULL;
  1355.  
  1356.     if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
  1357.     {
  1358.         /* Select a pending request to report. */
  1359.         unsigned i;
  1360.         for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
  1361.         {
  1362.             if (pThis->displayChangeData.aRequests[i].fPending)
  1363.             {
  1364.                 pDispRequest = &pThis->displayChangeData.aRequests[i];
  1365.                 /* Remember which request should be reported. */
  1366.                 pThis->displayChangeData.iCurrentMonitor = i;
  1367.                 Log3(("VMMDev: will report pending request for %u\n", i));
  1368.                 break;
  1369.             }
  1370.         }
  1371.  
  1372.         /* Check if there are more pending requests. */
  1373.         i++;
  1374.         for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
  1375.         {
  1376.             if (pThis->displayChangeData.aRequests[i].fPending)
  1377.             {
  1378.                 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
  1379.                 Log3(("VMMDev: another pending at %u\n", i));
  1380.                 break;
  1381.             }
  1382.         }
  1383.  
  1384.         if (pDispRequest)
  1385.         {
  1386.             /* Current request has been read at least once. */
  1387.             pDispRequest->fPending = false;
  1388.  
  1389.             /* Remember which resolution the client has queried, subsequent reads
  1390.              * will return the same values. */
  1391.             pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
  1392.             pThis->displayChangeData.fGuestSentChangeEventAck = true;
  1393.         }
  1394.         else
  1395.         {
  1396.              Log3(("VMMDev: no pending request!!!\n"));
  1397.         }
  1398.     }
  1399.  
  1400.     if (!pDispRequest)
  1401.     {
  1402.         Log3(("VMMDev: default to %d\n", pThis->displayChangeData.iCurrentMonitor));
  1403.         pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
  1404.     }
  1405.  
  1406.     if (pThis->displayChangeData.fGuestSentChangeEventAck)
  1407.     {
  1408.         pReq->xres    = pDispRequest->lastReadDisplayChangeRequest.xres;
  1409.         pReq->yres    = pDispRequest->lastReadDisplayChangeRequest.yres;
  1410.         pReq->bpp     = pDispRequest->lastReadDisplayChangeRequest.bpp;
  1411.         pReq->display = pDispRequest->lastReadDisplayChangeRequest.display;
  1412.     }
  1413.     else
  1414.     {
  1415.         /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
  1416.          * read the last valid video mode hint. This happens when the guest X server
  1417.          * determines the initial video mode. */
  1418.         pReq->xres    = pDispRequest->displayChangeRequest.xres;
  1419.         pReq->yres    = pDispRequest->displayChangeRequest.yres;
  1420.         pReq->bpp     = pDispRequest->displayChangeRequest.bpp;
  1421.         pReq->display = pDispRequest->displayChangeRequest.display;
  1422.     }
  1423.     Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
  1424.          pReq->xres, pReq->yres, pReq->bpp, pReq->display));
  1425.  
  1426.     return VINF_SUCCESS;
  1427. }
  1428.  
  1429.  
  1430. /**
  1431.  * Handles VMMDevReq_GetDisplayChangeRequestEx.
  1432.  *
  1433.  * @returns VBox status code that the guest should see.
  1434.  * @param   pThis           The VMMDev instance data.
  1435.  * @param   pReqHdr         The header of the request to handle.
  1436.  */
  1437. static int vmmdevReqHandler_GetDisplayChangeRequestEx(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1438. {
  1439.     VMMDevDisplayChangeRequestEx *pReq = (VMMDevDisplayChangeRequestEx *)pReqHdr;
  1440.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1441.  
  1442.     DISPLAYCHANGEREQUEST *pDispRequest = NULL;
  1443.  
  1444.     if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
  1445.     {
  1446.         /* Select a pending request to report. */
  1447.         unsigned i;
  1448.         for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
  1449.         {
  1450.             if (pThis->displayChangeData.aRequests[i].fPending)
  1451.             {
  1452.                 pDispRequest = &pThis->displayChangeData.aRequests[i];
  1453.                 /* Remember which request should be reported. */
  1454.                 pThis->displayChangeData.iCurrentMonitor = i;
  1455.                 Log3(("VMMDev: will report pending request for %d\n",
  1456.                       i));
  1457.                 break;
  1458.             }
  1459.         }
  1460.  
  1461.         /* Check if there are more pending requests. */
  1462.         i++;
  1463.         for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
  1464.         {
  1465.             if (pThis->displayChangeData.aRequests[i].fPending)
  1466.             {
  1467.                 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
  1468.                 Log3(("VMMDev: another pending at %d\n",
  1469.                       i));
  1470.                 break;
  1471.             }
  1472.         }
  1473.  
  1474.         if (pDispRequest)
  1475.         {
  1476.             /* Current request has been read at least once. */
  1477.             pDispRequest->fPending = false;
  1478.  
  1479.             /* Remember which resolution the client has queried, subsequent reads
  1480.              * will return the same values. */
  1481.             pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
  1482.             pThis->displayChangeData.fGuestSentChangeEventAck = true;
  1483.         }
  1484.         else
  1485.         {
  1486.              Log3(("VMMDev: no pending request!!!\n"));
  1487.         }
  1488.     }
  1489.  
  1490.     if (!pDispRequest)
  1491.     {
  1492.         Log3(("VMMDev: default to %d\n",
  1493.               pThis->displayChangeData.iCurrentMonitor));
  1494.         pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
  1495.     }
  1496.  
  1497.     if (pThis->displayChangeData.fGuestSentChangeEventAck)
  1498.     {
  1499.         pReq->xres          = pDispRequest->lastReadDisplayChangeRequest.xres;
  1500.         pReq->yres          = pDispRequest->lastReadDisplayChangeRequest.yres;
  1501.         pReq->bpp           = pDispRequest->lastReadDisplayChangeRequest.bpp;
  1502.         pReq->display       = pDispRequest->lastReadDisplayChangeRequest.display;
  1503.         pReq->cxOrigin      = pDispRequest->lastReadDisplayChangeRequest.xOrigin;
  1504.         pReq->cyOrigin      = pDispRequest->lastReadDisplayChangeRequest.yOrigin;
  1505.         pReq->fEnabled      = pDispRequest->lastReadDisplayChangeRequest.fEnabled;
  1506.         pReq->fChangeOrigin = pDispRequest->lastReadDisplayChangeRequest.fChangeOrigin;
  1507.     }
  1508.     else
  1509.     {
  1510.         /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
  1511.          * read the last valid video mode hint. This happens when the guest X server
  1512.          * determines the initial video mode. */
  1513.         pReq->xres          = pDispRequest->displayChangeRequest.xres;
  1514.         pReq->yres          = pDispRequest->displayChangeRequest.yres;
  1515.         pReq->bpp           = pDispRequest->displayChangeRequest.bpp;
  1516.         pReq->display       = pDispRequest->displayChangeRequest.display;
  1517.         pReq->cxOrigin      = pDispRequest->displayChangeRequest.xOrigin;
  1518.         pReq->cyOrigin      = pDispRequest->displayChangeRequest.yOrigin;
  1519.         pReq->fEnabled      = pDispRequest->displayChangeRequest.fEnabled;
  1520.         pReq->fChangeOrigin = pDispRequest->displayChangeRequest.fChangeOrigin;
  1521.  
  1522.     }
  1523.     Log(("VMMDevEx: returning display change request xres = %d, yres = %d, bpp = %d id %d xPos = %d, yPos = %d & Enabled=%d\n",
  1524.          pReq->xres, pReq->yres, pReq->bpp, pReq->display, pReq->cxOrigin, pReq->cyOrigin, pReq->fEnabled));
  1525.  
  1526.     return VINF_SUCCESS;
  1527. }
  1528.  
  1529.  
  1530. /**
  1531.  * Handles VMMDevReq_VideoModeSupported.
  1532.  *
  1533.  * Query whether the given video mode is supported.
  1534.  *
  1535.  * @returns VBox status code that the guest should see.
  1536.  * @param   pThis           The VMMDev instance data.
  1537.  * @param   pReqHdr         The header of the request to handle.
  1538.  */
  1539. static int vmmdevReqHandler_VideoModeSupported(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1540. {
  1541.     VMMDevVideoModeSupportedRequest *pReq = (VMMDevVideoModeSupportedRequest *)pReqHdr;
  1542.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1543.  
  1544.     /* forward the call */
  1545.     return pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
  1546.                                               0, /* primary screen. */
  1547.                                               pReq->width,
  1548.                                               pReq->height,
  1549.                                               pReq->bpp,
  1550.                                               &pReq->fSupported);
  1551. }
  1552.  
  1553.  
  1554. /**
  1555.  * Handles VMMDevReq_VideoModeSupported2.
  1556.  *
  1557.  * Query whether the given video mode is supported for a specific display
  1558.  *
  1559.  * @returns VBox status code that the guest should see.
  1560.  * @param   pThis           The VMMDev instance data.
  1561.  * @param   pReqHdr         The header of the request to handle.
  1562.  */
  1563. static int vmmdevReqHandler_VideoModeSupported2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1564. {
  1565.     VMMDevVideoModeSupportedRequest2 *pReq = (VMMDevVideoModeSupportedRequest2 *)pReqHdr;
  1566.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1567.  
  1568.     /* forward the call */
  1569.     return pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
  1570.                                               pReq->display,
  1571.                                               pReq->width,
  1572.                                               pReq->height,
  1573.                                               pReq->bpp,
  1574.                                               &pReq->fSupported);
  1575. }
  1576.  
  1577.  
  1578.  
  1579. /**
  1580.  * Handles VMMDevReq_GetHeightReduction.
  1581.  *
  1582.  * @returns VBox status code that the guest should see.
  1583.  * @param   pThis           The VMMDev instance data.
  1584.  * @param   pReqHdr         The header of the request to handle.
  1585.  */
  1586. static int vmmdevReqHandler_GetHeightReduction(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1587. {
  1588.     VMMDevGetHeightReductionRequest *pReq = (VMMDevGetHeightReductionRequest *)pReqHdr;
  1589.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1590.  
  1591.     /* forward the call */
  1592.     return pThis->pDrv->pfnGetHeightReduction(pThis->pDrv, &pReq->heightReduction);
  1593. }
  1594.  
  1595.  
  1596. /**
  1597.  * Handles VMMDevReq_AcknowledgeEvents.
  1598.  *
  1599.  * @returns VBox status code that the guest should see.
  1600.  * @param   pThis           The VMMDev instance data.
  1601.  * @param   pReqHdr         The header of the request to handle.
  1602.  */
  1603. static int vmmdevReqHandler_AcknowledgeEvents(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1604. {
  1605.     VMMDevEvents *pReq = (VMMDevEvents *)pReqHdr;
  1606.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1607.  
  1608.     if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
  1609.     {
  1610.         if (pThis->fNewGuestFilterMask)
  1611.         {
  1612.             pThis->fNewGuestFilterMask = false;
  1613.             pThis->u32GuestFilterMask = pThis->u32NewGuestFilterMask;
  1614.         }
  1615.  
  1616.         pReq->events = pThis->u32HostEventFlags & pThis->u32GuestFilterMask;
  1617.  
  1618.         pThis->u32HostEventFlags &= ~pThis->u32GuestFilterMask;
  1619.         pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = false;
  1620.         PDMDevHlpPCISetIrqNoWait(pThis->pDevIns, 0, 0);
  1621.     }
  1622.     else
  1623.         vmmdevSetIRQ_Legacy(pThis);
  1624.     return VINF_SUCCESS;
  1625. }
  1626.  
  1627.  
  1628. /**
  1629.  * Handles VMMDevReq_CtlGuestFilterMask.
  1630.  *
  1631.  * @returns VBox status code that the guest should see.
  1632.  * @param   pThis           The VMMDev instance data.
  1633.  * @param   pReqHdr         The header of the request to handle.
  1634.  */
  1635. static int vmmdevReqHandler_CtlGuestFilterMask(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1636. {
  1637.     VMMDevCtlGuestFilterMask *pReq = (VMMDevCtlGuestFilterMask *)pReqHdr;
  1638.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1639.  
  1640.     LogRelFlow(("VMMDev: vmmdevReqHandler_CtlGuestFilterMask: OR mask: %#x, NOT mask: %#x\n", pReq->u32OrMask, pReq->u32NotMask));
  1641.  
  1642.     /* HGCM event notification is enabled by the VMMDev device
  1643.      * automatically when any HGCM command is issued.  The guest
  1644.      * cannot disable these notifications. */
  1645.     VMMDevCtlSetGuestFilterMask(pThis, pReq->u32OrMask, pReq->u32NotMask & ~VMMDEV_EVENT_HGCM);
  1646.     return VINF_SUCCESS;
  1647. }
  1648.  
  1649. #ifdef VBOX_WITH_HGCM
  1650.  
  1651. /**
  1652.  * Handles VMMDevReq_HGCMConnect.
  1653.  *
  1654.  * @returns VBox status code that the guest should see.
  1655.  * @param   pThis           The VMMDev instance data.
  1656.  * @param   pReqHdr         The header of the request to handle.
  1657.  * @param   GCPhysReqHdr    The guest physical address of the request header.
  1658.  */
  1659. static int vmmdevReqHandler_HGCMConnect(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
  1660. {
  1661.     VMMDevHGCMConnect *pReq = (VMMDevHGCMConnect *)pReqHdr;
  1662.     AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this is >= ... */
  1663.  
  1664.     if (pThis->pHGCMDrv)
  1665.     {
  1666.         Log(("VMMDevReq_HGCMConnect\n"));
  1667.         return vmmdevHGCMConnect(pThis, pReq, GCPhysReqHdr);
  1668.     }
  1669.  
  1670.     Log(("VMMDevReq_HGCMConnect: HGCM Connector is NULL!\n"));
  1671.     return VERR_NOT_SUPPORTED;
  1672. }
  1673.  
  1674.  
  1675. /**
  1676.  * Handles VMMDevReq_HGCMDisconnect.
  1677.  *
  1678.  * @returns VBox status code that the guest should see.
  1679.  * @param   pThis           The VMMDev instance data.
  1680.  * @param   pReqHdr         The header of the request to handle.
  1681.  * @param   GCPhysReqHdr    The guest physical address of the request header.
  1682.  */
  1683. static int vmmdevReqHandler_HGCMDisconnect(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
  1684. {
  1685.     VMMDevHGCMDisconnect *pReq = (VMMDevHGCMDisconnect *)pReqHdr;
  1686.     AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER);  /** @todo Not sure why this >= ... */
  1687.  
  1688.     if (pThis->pHGCMDrv)
  1689.     {
  1690.         Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
  1691.         return vmmdevHGCMDisconnect(pThis, pReq, GCPhysReqHdr);
  1692.     }
  1693.  
  1694.     Log(("VMMDevReq_VMMDevHGCMDisconnect: HGCM Connector is NULL!\n"));
  1695.     return VERR_NOT_SUPPORTED;
  1696. }
  1697.  
  1698.  
  1699. /**
  1700.  * Handles VMMDevReq_HGCMCall.
  1701.  *
  1702.  * @returns VBox status code that the guest should see.
  1703.  * @param   pThis           The VMMDev instance data.
  1704.  * @param   pReqHdr         The header of the request to handle.
  1705.  * @param   GCPhysReqHdr    The guest physical address of the request header.
  1706.  */
  1707. static int vmmdevReqHandler_HGCMCall(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
  1708. {
  1709.     VMMDevHGCMCall *pReq = (VMMDevHGCMCall *)pReqHdr;
  1710.     AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER);
  1711.  
  1712.     if (pThis->pHGCMDrv)
  1713.     {
  1714.         Log2(("VMMDevReq_HGCMCall: sizeof(VMMDevHGCMRequest) = %04X\n", sizeof(VMMDevHGCMCall)));
  1715.         Log2(("%.*Rhxd\n", pReq->header.header.size, pReq));
  1716.  
  1717. #ifdef VBOX_WITH_64_BITS_GUESTS
  1718.         bool f64Bits = (pReq->header.header.requestType == VMMDevReq_HGCMCall64);
  1719. #else
  1720.         bool f64Bits = false;
  1721. #endif /* VBOX_WITH_64_BITS_GUESTS */
  1722.  
  1723.         return vmmdevHGCMCall(pThis, pReq, pReq->header.header.size, GCPhysReqHdr, f64Bits);
  1724.     }
  1725.  
  1726.     Log(("VMMDevReq_HGCMCall: HGCM Connector is NULL!\n"));
  1727.     return VERR_NOT_SUPPORTED;
  1728. }
  1729.  
  1730. /**
  1731.  * Handles VMMDevReq_HGCMCancel.
  1732.  *
  1733.  * @returns VBox status code that the guest should see.
  1734.  * @param   pThis           The VMMDev instance data.
  1735.  * @param   pReqHdr         The header of the request to handle.
  1736.  * @param   GCPhysReqHdr    The guest physical address of the request header.
  1737.  */
  1738. static int vmmdevReqHandler_HGCMCancel(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
  1739. {
  1740.     VMMDevHGCMCancel *pReq = (VMMDevHGCMCancel *)pReqHdr;
  1741.     AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER);  /** @todo Not sure why this >= ... */
  1742.  
  1743.     if (pThis->pHGCMDrv)
  1744.     {
  1745.         Log(("VMMDevReq_VMMDevHGCMCancel\n"));
  1746.         return vmmdevHGCMCancel(pThis, pReq, GCPhysReqHdr);
  1747.     }
  1748.  
  1749.     Log(("VMMDevReq_VMMDevHGCMCancel: HGCM Connector is NULL!\n"));
  1750.     return VERR_NOT_SUPPORTED;
  1751. }
  1752.  
  1753.  
  1754. /**
  1755.  * Handles VMMDevReq_HGCMCancel2.
  1756.  *
  1757.  * @returns VBox status code that the guest should see.
  1758.  * @param   pThis           The VMMDev instance data.
  1759.  * @param   pReqHdr         The header of the request to handle.
  1760.  */
  1761. static int vmmdevReqHandler_HGCMCancel2(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1762. {
  1763.     VMMDevHGCMCancel2 *pReq = (VMMDevHGCMCancel2 *)pReqHdr;
  1764.     AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);  /** @todo Not sure why this >= ... */
  1765.  
  1766.     if (pThis->pHGCMDrv)
  1767.     {
  1768.         Log(("VMMDevReq_HGCMCancel2\n"));
  1769.         return vmmdevHGCMCancel2(pThis, pReq->physReqToCancel);
  1770.     }
  1771.  
  1772.     Log(("VMMDevReq_HGCMConnect2: HGCM Connector is NULL!\n"));
  1773.     return VERR_NOT_SUPPORTED;
  1774. }
  1775.  
  1776. #endif /* VBOX_WITH_HGCM */
  1777.  
  1778.  
  1779. /**
  1780.  * Handles VMMDevReq_VideoAccelEnable.
  1781.  *
  1782.  * @returns VBox status code that the guest should see.
  1783.  * @param   pThis           The VMMDev instance data.
  1784.  * @param   pReqHdr         The header of the request to handle.
  1785.  */
  1786. static int vmmdevReqHandler_VideoAccelEnable(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1787. {
  1788.     VMMDevVideoAccelEnable *pReq = (VMMDevVideoAccelEnable *)pReqHdr;
  1789.     AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);  /** @todo Not sure why this >= ... */
  1790.  
  1791.     if (!pThis->pDrv)
  1792.     {
  1793.         Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!\n"));
  1794.         return VERR_NOT_SUPPORTED;
  1795.     }
  1796.  
  1797.     if (pReq->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
  1798.     {
  1799.         /* The guest driver seems compiled with different headers. */
  1800.         LogRelMax(16,("VMMDevReq_VideoAccelEnable guest ring buffer size %#x, should be %#x!!\n", pReq->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
  1801.         return VERR_INVALID_PARAMETER;
  1802.     }
  1803.  
  1804.     /* The request is correct. */
  1805.     pReq->fu32Status |= VBVA_F_STATUS_ACCEPTED;
  1806.  
  1807.     LogFlow(("VMMDevReq_VideoAccelEnable pReq->u32Enable = %d\n", pReq->u32Enable));
  1808.  
  1809.     int rc = pReq->u32Enable
  1810.            ? pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, true, &pThis->pVMMDevRAMR3->vbvaMemory)
  1811.            : pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, false, NULL);
  1812.  
  1813.     if (   pReq->u32Enable
  1814.         && RT_SUCCESS(rc))
  1815.     {
  1816.         pReq->fu32Status |= VBVA_F_STATUS_ENABLED;
  1817.  
  1818.         /* Remember that guest successfully enabled acceleration.
  1819.          * We need to reestablish it on restoring the VM from saved state.
  1820.          */
  1821.         pThis->u32VideoAccelEnabled = 1;
  1822.     }
  1823.     else
  1824.     {
  1825.         /* The acceleration was not enabled. Remember that. */
  1826.         pThis->u32VideoAccelEnabled = 0;
  1827.     }
  1828.     return VINF_SUCCESS;
  1829. }
  1830.  
  1831.  
  1832. /**
  1833.  * Handles VMMDevReq_VideoAccelFlush.
  1834.  *
  1835.  * @returns VBox status code that the guest should see.
  1836.  * @param   pThis           The VMMDev instance data.
  1837.  * @param   pReqHdr         The header of the request to handle.
  1838.  */
  1839. static int vmmdevReqHandler_VideoAccelFlush(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1840. {
  1841.     VMMDevVideoAccelFlush *pReq = (VMMDevVideoAccelFlush *)pReqHdr;
  1842.     AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);  /** @todo Not sure why this >= ... */
  1843.  
  1844.     if (!pThis->pDrv)
  1845.     {
  1846.         Log(("VMMDevReq_VideoAccelFlush: Connector is NULL!!!\n"));
  1847.         return VERR_NOT_SUPPORTED;
  1848.     }
  1849.  
  1850.     pThis->pDrv->pfnVideoAccelFlush(pThis->pDrv);
  1851.     return VINF_SUCCESS;
  1852. }
  1853.  
  1854.  
  1855. /**
  1856.  * Handles VMMDevReq_VideoSetVisibleRegion.
  1857.  *
  1858.  * @returns VBox status code that the guest should see.
  1859.  * @param   pThis           The VMMDev instance data.
  1860.  * @param   pReqHdr         The header of the request to handle.
  1861.  */
  1862. static int vmmdevReqHandler_VideoSetVisibleRegion(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1863. {
  1864.     VMMDevVideoSetVisibleRegion *pReq = (VMMDevVideoSetVisibleRegion *)pReqHdr;
  1865.     AssertMsgReturn(pReq->header.size + sizeof(RTRECT) >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1866.  
  1867.     if (!pThis->pDrv)
  1868.     {
  1869.         Log(("VMMDevReq_VideoSetVisibleRegion: Connector is NULL!!!\n"));
  1870.         return VERR_NOT_SUPPORTED;
  1871.     }
  1872.  
  1873.     if (   pReq->cRect > _1M /* restrict to sane range */
  1874.         || pReq->header.size != sizeof(VMMDevVideoSetVisibleRegion) + pReq->cRect * sizeof(RTRECT) - sizeof(RTRECT))
  1875.     {
  1876.         Log(("VMMDevReq_VideoSetVisibleRegion: cRects=%#x doesn't match size=%#x or is out of bounds\n",
  1877.              pReq->cRect, pReq->header.size));
  1878.         return VERR_INVALID_PARAMETER;
  1879.     }
  1880.  
  1881.     Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", pReq->cRect));
  1882.     /* forward the call */
  1883.     return pThis->pDrv->pfnSetVisibleRegion(pThis->pDrv, pReq->cRect, &pReq->Rect);
  1884. }
  1885.  
  1886.  
  1887. /**
  1888.  * Handles VMMDevReq_GetSeamlessChangeRequest.
  1889.  *
  1890.  * @returns VBox status code that the guest should see.
  1891.  * @param   pThis           The VMMDev instance data.
  1892.  * @param   pReqHdr         The header of the request to handle.
  1893.  */
  1894. static int vmmdevReqHandler_GetSeamlessChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1895. {
  1896.     VMMDevSeamlessChangeRequest *pReq = (VMMDevSeamlessChangeRequest *)pReqHdr;
  1897.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1898.  
  1899.     /* just pass on the information */
  1900.     Log(("VMMDev: returning seamless change request mode=%d\n", pThis->fSeamlessEnabled));
  1901.     if (pThis->fSeamlessEnabled)
  1902.         pReq->mode = VMMDev_Seamless_Visible_Region;
  1903.     else
  1904.         pReq->mode = VMMDev_Seamless_Disabled;
  1905.  
  1906.     if (pReq->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
  1907.     {
  1908.         /* Remember which mode the client has queried. */
  1909.         pThis->fLastSeamlessEnabled = pThis->fSeamlessEnabled;
  1910.     }
  1911.  
  1912.     return VINF_SUCCESS;
  1913. }
  1914.  
  1915.  
  1916. /**
  1917.  * Handles VMMDevReq_GetVRDPChangeRequest.
  1918.  *
  1919.  * @returns VBox status code that the guest should see.
  1920.  * @param   pThis           The VMMDev instance data.
  1921.  * @param   pReqHdr         The header of the request to handle.
  1922.  */
  1923. static int vmmdevReqHandler_GetVRDPChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1924. {
  1925.     VMMDevVRDPChangeRequest *pReq = (VMMDevVRDPChangeRequest *)pReqHdr;
  1926.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1927.  
  1928.     /* just pass on the information */
  1929.     Log(("VMMDev: returning VRDP status %d level %d\n", pThis->fVRDPEnabled, pThis->uVRDPExperienceLevel));
  1930.  
  1931.     pReq->u8VRDPActive = pThis->fVRDPEnabled;
  1932.     pReq->u32VRDPExperienceLevel = pThis->uVRDPExperienceLevel;
  1933.  
  1934.     return VINF_SUCCESS;
  1935. }
  1936.  
  1937.  
  1938. /**
  1939.  * Handles VMMDevReq_GetMemBalloonChangeRequest.
  1940.  *
  1941.  * @returns VBox status code that the guest should see.
  1942.  * @param   pThis           The VMMDev instance data.
  1943.  * @param   pReqHdr         The header of the request to handle.
  1944.  */
  1945. static int vmmdevReqHandler_GetMemBalloonChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1946. {
  1947.     VMMDevGetMemBalloonChangeRequest *pReq = (VMMDevGetMemBalloonChangeRequest *)pReqHdr;
  1948.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1949.  
  1950.     /* just pass on the information */
  1951.     Log(("VMMDev: returning memory balloon size =%d\n", pThis->cMbMemoryBalloon));
  1952.     pReq->cBalloonChunks = pThis->cMbMemoryBalloon;
  1953.     pReq->cPhysMemChunks = pThis->cbGuestRAM / (uint64_t)_1M;
  1954.  
  1955.     if (pReq->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
  1956.     {
  1957.         /* Remember which mode the client has queried. */
  1958.         pThis->cMbMemoryBalloonLast = pThis->cMbMemoryBalloon;
  1959.     }
  1960.  
  1961.     return VINF_SUCCESS;
  1962. }
  1963.  
  1964.  
  1965. /**
  1966.  * Handles VMMDevReq_ChangeMemBalloon.
  1967.  *
  1968.  * @returns VBox status code that the guest should see.
  1969.  * @param   pThis           The VMMDev instance data.
  1970.  * @param   pReqHdr         The header of the request to handle.
  1971.  */
  1972. static int vmmdevReqHandler_ChangeMemBalloon(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1973. {
  1974.     VMMDevChangeMemBalloon *pReq = (VMMDevChangeMemBalloon *)pReqHdr;
  1975.     AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1976.     AssertMsgReturn(pReq->cPages      == VMMDEV_MEMORY_BALLOON_CHUNK_PAGES, ("%u\n", pReq->cPages), VERR_INVALID_PARAMETER);
  1977.     AssertMsgReturn(pReq->header.size == (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[pReq->cPages]),
  1978.                     ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  1979.  
  1980.     Log(("VMMDevReq_ChangeMemBalloon\n"));
  1981.     int rc = PGMR3PhysChangeMemBalloon(PDMDevHlpGetVM(pThis->pDevIns), !!pReq->fInflate, pReq->cPages, pReq->aPhysPage);
  1982.     if (pReq->fInflate)
  1983.         STAM_REL_U32_INC(&pThis->StatMemBalloonChunks);
  1984.     else
  1985.         STAM_REL_U32_DEC(&pThis->StatMemBalloonChunks);
  1986.     return rc;
  1987. }
  1988.  
  1989.  
  1990. /**
  1991.  * Handles VMMDevReq_GetStatisticsChangeRequest.
  1992.  *
  1993.  * @returns VBox status code that the guest should see.
  1994.  * @param   pThis           The VMMDev instance data.
  1995.  * @param   pReqHdr         The header of the request to handle.
  1996.  */
  1997. static int vmmdevReqHandler_GetStatisticsChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  1998. {
  1999.     VMMDevGetStatisticsChangeRequest *pReq = (VMMDevGetStatisticsChangeRequest *)pReqHdr;
  2000.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2001.  
  2002.     Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
  2003.     /* just pass on the information */
  2004.     Log(("VMMDev: returning statistics interval %d seconds\n", pThis->u32StatIntervalSize));
  2005.     pReq->u32StatInterval = pThis->u32StatIntervalSize;
  2006.  
  2007.     if (pReq->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
  2008.     {
  2009.         /* Remember which mode the client has queried. */
  2010.         pThis->u32LastStatIntervalSize= pThis->u32StatIntervalSize;
  2011.     }
  2012.  
  2013.     return VINF_SUCCESS;
  2014. }
  2015.  
  2016.  
  2017. /**
  2018.  * Handles VMMDevReq_ReportGuestStats.
  2019.  *
  2020.  * @returns VBox status code that the guest should see.
  2021.  * @param   pThis           The VMMDev instance data.
  2022.  * @param   pReqHdr         The header of the request to handle.
  2023.  */
  2024. static int vmmdevReqHandler_ReportGuestStats(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2025. {
  2026.     VMMDevReportGuestStats *pReq = (VMMDevReportGuestStats *)pReqHdr;
  2027.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2028.  
  2029.     Log(("VMMDevReq_ReportGuestStats\n"));
  2030. #ifdef LOG_ENABLED
  2031.     VBoxGuestStatistics *pGuestStats = &pReq->guestStats;
  2032.  
  2033.     Log(("Current statistics:\n"));
  2034.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
  2035.         Log(("CPU%u: CPU Load Idle          %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
  2036.  
  2037.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
  2038.         Log(("CPU%u: CPU Load Kernel        %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
  2039.  
  2040.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
  2041.         Log(("CPU%u: CPU Load User          %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
  2042.  
  2043.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
  2044.         Log(("CPU%u: Thread                 %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
  2045.  
  2046.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
  2047.         Log(("CPU%u: Processes              %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
  2048.  
  2049.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
  2050.         Log(("CPU%u: Handles                %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
  2051.  
  2052.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
  2053.         Log(("CPU%u: Memory Load            %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
  2054.  
  2055.     /* Note that reported values are in pages; upper layers expect them in megabytes */
  2056.     Log(("CPU%u: Page size              %-4d bytes\n", pGuestStats->u32CpuId, pGuestStats->u32PageSize));
  2057.     Assert(pGuestStats->u32PageSize == 4096);
  2058.  
  2059.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
  2060.         Log(("CPU%u: Total physical memory  %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/_4K)-1) / (_1M/_4K)));
  2061.  
  2062.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
  2063.         Log(("CPU%u: Free physical memory   %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/_4K)));
  2064.  
  2065.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
  2066.         Log(("CPU%u: Memory balloon size    %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/_4K)));
  2067.  
  2068.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
  2069.         Log(("CPU%u: Committed memory       %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/_4K)));
  2070.  
  2071.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
  2072.         Log(("CPU%u: Total kernel memory    %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/_4K)));
  2073.  
  2074.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
  2075.         Log(("CPU%u: Paged kernel memory    %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/_4K)));
  2076.  
  2077.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
  2078.         Log(("CPU%u: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/_4K)));
  2079.  
  2080.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
  2081.         Log(("CPU%u: System cache size      %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/_4K)));
  2082.  
  2083.     if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
  2084.         Log(("CPU%u: Page file size         %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/_4K)));
  2085.     Log(("Statistics end *******************\n"));
  2086. #endif /* LOG_ENABLED */
  2087.  
  2088.     /* forward the call */
  2089.     return pThis->pDrv->pfnReportStatistics(pThis->pDrv, &pReq->guestStats);
  2090. }
  2091.  
  2092.  
  2093. /**
  2094.  * Handles VMMDevReq_QueryCredentials.
  2095.  *
  2096.  * @returns VBox status code that the guest should see.
  2097.  * @param   pThis           The VMMDev instance data.
  2098.  * @param   pReqHdr         The header of the request to handle.
  2099.  */
  2100. static int vmmdevReqHandler_QueryCredentials(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2101. {
  2102.     VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
  2103.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2104.  
  2105.     /* let's start by nulling out the data */
  2106.     memset(pReq->szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2107.     memset(pReq->szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2108.     memset(pReq->szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2109.  
  2110.     /* should we return whether we got credentials for a logon? */
  2111.     if (pReq->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
  2112.     {
  2113.         if (   pThis->pCredentials->Logon.szUserName[0]
  2114.             || pThis->pCredentials->Logon.szPassword[0]
  2115.             || pThis->pCredentials->Logon.szDomain[0])
  2116.             pReq->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
  2117.         else
  2118.             pReq->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
  2119.     }
  2120.  
  2121.     /* does the guest want to read logon credentials? */
  2122.     if (pReq->u32Flags & VMMDEV_CREDENTIALS_READ)
  2123.     {
  2124.         if (pThis->pCredentials->Logon.szUserName[0])
  2125.             strcpy(pReq->szUserName, pThis->pCredentials->Logon.szUserName);
  2126.         if (pThis->pCredentials->Logon.szPassword[0])
  2127.             strcpy(pReq->szPassword, pThis->pCredentials->Logon.szPassword);
  2128.         if (pThis->pCredentials->Logon.szDomain[0])
  2129.             strcpy(pReq->szDomain, pThis->pCredentials->Logon.szDomain);
  2130.         if (!pThis->pCredentials->Logon.fAllowInteractiveLogon)
  2131.             pReq->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
  2132.         else
  2133.             pReq->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
  2134.     }
  2135.  
  2136.     if (!pThis->fKeepCredentials)
  2137.     {
  2138.         /* does the caller want us to destroy the logon credentials? */
  2139.         if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
  2140.         {
  2141.             memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2142.             memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2143.             memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2144.         }
  2145.     }
  2146.  
  2147.     /* does the guest want to read credentials for verification? */
  2148.     if (pReq->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
  2149.     {
  2150.         if (pThis->pCredentials->Judge.szUserName[0])
  2151.             strcpy(pReq->szUserName, pThis->pCredentials->Judge.szUserName);
  2152.         if (pThis->pCredentials->Judge.szPassword[0])
  2153.             strcpy(pReq->szPassword, pThis->pCredentials->Judge.szPassword);
  2154.         if (pThis->pCredentials->Judge.szDomain[0])
  2155.             strcpy(pReq->szDomain, pThis->pCredentials->Judge.szDomain);
  2156.     }
  2157.  
  2158.     /* does the caller want us to destroy the judgement credentials? */
  2159.     if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
  2160.     {
  2161.         memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2162.         memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2163.         memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  2164.     }
  2165.  
  2166.     return VINF_SUCCESS;
  2167. }
  2168.  
  2169.  
  2170. /**
  2171.  * Handles VMMDevReq_ReportCredentialsJudgement.
  2172.  *
  2173.  * @returns VBox status code that the guest should see.
  2174.  * @param   pThis           The VMMDev instance data.
  2175.  * @param   pReqHdr         The header of the request to handle.
  2176.  */
  2177. static int vmmdevReqHandler_ReportCredentialsJudgement(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2178. {
  2179.     VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
  2180.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2181.  
  2182.     /* what does the guest think about the credentials? (note: the order is important here!) */
  2183.     if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
  2184.         pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
  2185.     else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
  2186.         pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
  2187.     else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
  2188.         pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
  2189.     else
  2190.     {
  2191.         Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", pReq->u32Flags));
  2192.         /** @todo why don't we return VERR_INVALID_PARAMETER to the guest? */
  2193.     }
  2194.  
  2195.     return VINF_SUCCESS;
  2196. }
  2197.  
  2198.  
  2199. /**
  2200.  * Handles VMMDevReq_GetHostVersion.
  2201.  *
  2202.  * @returns VBox status code that the guest should see.
  2203.  * @param   pReqHdr         The header of the request to handle.
  2204.  * @since   3.1.0
  2205.  * @note    The ring-0 VBoxGuestLib uses this to check whether
  2206.  *          VMMDevHGCMParmType_PageList is supported.
  2207.  */
  2208. static int vmmdevReqHandler_GetHostVersion(VMMDevRequestHeader *pReqHdr)
  2209. {
  2210.     VMMDevReqHostVersion *pReq = (VMMDevReqHostVersion *)pReqHdr;
  2211.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2212.  
  2213.     pReq->major     = RTBldCfgVersionMajor();
  2214.     pReq->minor     = RTBldCfgVersionMinor();
  2215.     pReq->build     = RTBldCfgVersionBuild();
  2216.     pReq->revision  = RTBldCfgRevision();
  2217.     pReq->features  = VMMDEV_HVF_HGCM_PHYS_PAGE_LIST;
  2218.     return VINF_SUCCESS;
  2219. }
  2220.  
  2221.  
  2222. /**
  2223.  * Handles VMMDevReq_GetCpuHotPlugRequest.
  2224.  *
  2225.  * @returns VBox status code that the guest should see.
  2226.  * @param   pThis           The VMMDev instance data.
  2227.  * @param   pReqHdr         The header of the request to handle.
  2228.  */
  2229. static int vmmdevReqHandler_GetCpuHotPlugRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2230. {
  2231.     VMMDevGetCpuHotPlugRequest *pReq = (VMMDevGetCpuHotPlugRequest *)pReqHdr;
  2232.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2233.  
  2234.     pReq->enmEventType  = pThis->enmCpuHotPlugEvent;
  2235.     pReq->idCpuCore     = pThis->idCpuCore;
  2236.     pReq->idCpuPackage  = pThis->idCpuPackage;
  2237.  
  2238.     /* Clear the event */
  2239.     pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_None;
  2240.     pThis->idCpuCore          = UINT32_MAX;
  2241.     pThis->idCpuPackage       = UINT32_MAX;
  2242.  
  2243.     return VINF_SUCCESS;
  2244. }
  2245.  
  2246.  
  2247. /**
  2248.  * Handles VMMDevReq_SetCpuHotPlugStatus.
  2249.  *
  2250.  * @returns VBox status code that the guest should see.
  2251.  * @param   pThis           The VMMDev instance data.
  2252.  * @param   pReqHdr         The header of the request to handle.
  2253.  */
  2254. static int vmmdevReqHandler_SetCpuHotPlugStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2255. {
  2256.     VMMDevCpuHotPlugStatusRequest *pReq = (VMMDevCpuHotPlugStatusRequest *)pReqHdr;
  2257.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2258.  
  2259.     if (pReq->enmStatusType == VMMDevCpuStatusType_Disable)
  2260.         pThis->fCpuHotPlugEventsEnabled = false;
  2261.     else if (pReq->enmStatusType == VMMDevCpuStatusType_Enable)
  2262.         pThis->fCpuHotPlugEventsEnabled = true;
  2263.     else
  2264.         return VERR_INVALID_PARAMETER;
  2265.     return VINF_SUCCESS;
  2266. }
  2267.  
  2268.  
  2269. #ifdef DEBUG
  2270. /**
  2271.  * Handles VMMDevReq_LogString.
  2272.  *
  2273.  * @returns VBox status code that the guest should see.
  2274.  * @param   pReqHdr         The header of the request to handle.
  2275.  */
  2276. static int vmmdevReqHandler_LogString(VMMDevRequestHeader *pReqHdr)
  2277. {
  2278.     VMMDevReqLogString *pReq = (VMMDevReqLogString *)pReqHdr;
  2279.     AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2280.     AssertMsgReturn(pReq->szString[pReq->header.size - RT_OFFSETOF(VMMDevReqLogString, szString) - 1] == '\0',
  2281.                     ("not null terminated\n"), VERR_INVALID_PARAMETER);
  2282.  
  2283.     LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("DEBUG LOG: %s", pReq->szString));
  2284.     return VINF_SUCCESS;
  2285. }
  2286. #endif /* DEBUG */
  2287.  
  2288. /**
  2289.  * Handles VMMDevReq_GetSessionId.
  2290.  *
  2291.  * Get a unique "session" ID for this VM, where the ID will be different after each
  2292.  * start, reset or restore of the VM.  This can be used for restore detection
  2293.  * inside the guest.
  2294.  *
  2295.  * @returns VBox status code that the guest should see.
  2296.  * @param   pThis           The VMMDev instance data.
  2297.  * @param   pReqHdr         The header of the request to handle.
  2298.  */
  2299. static int vmmdevReqHandler_GetSessionId(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2300. {
  2301.     VMMDevReqSessionId *pReq = (VMMDevReqSessionId *)pReqHdr;
  2302.     AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2303.  
  2304.     pReq->idSession = pThis->idSession;
  2305.     return VINF_SUCCESS;
  2306. }
  2307.  
  2308.  
  2309. #ifdef VBOX_WITH_PAGE_SHARING
  2310.  
  2311. /**
  2312.  * Handles VMMDevReq_RegisterSharedModule.
  2313.  *
  2314.  * @returns VBox status code that the guest should see.
  2315.  * @param   pThis           The VMMDev instance data.
  2316.  * @param   pReqHdr         The header of the request to handle.
  2317.  */
  2318. static int vmmdevReqHandler_RegisterSharedModule(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2319. {
  2320.     /*
  2321.      * Basic input validation (more done by GMM).
  2322.      */
  2323.     VMMDevSharedModuleRegistrationRequest *pReq = (VMMDevSharedModuleRegistrationRequest *)pReqHdr;
  2324.     AssertMsgReturn(pReq->header.size >= sizeof(VMMDevSharedModuleRegistrationRequest),
  2325.                     ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2326.     AssertMsgReturn(pReq->header.size == RT_UOFFSETOF(VMMDevSharedModuleRegistrationRequest, aRegions[pReq->cRegions]),
  2327.                     ("%u cRegions=%u\n", pReq->header.size, pReq->cRegions), VERR_INVALID_PARAMETER);
  2328.  
  2329.     AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
  2330.     AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
  2331.     int rc = RTStrValidateEncoding(pReq->szName);
  2332.     AssertRCReturn(rc, rc);
  2333.     rc = RTStrValidateEncoding(pReq->szVersion);
  2334.     AssertRCReturn(rc, rc);
  2335.  
  2336.     /*
  2337.      * Forward the request to the VMM.
  2338.      */
  2339.     return PGMR3SharedModuleRegister(PDMDevHlpGetVM(pThis->pDevIns), pReq->enmGuestOS, pReq->szName, pReq->szVersion,
  2340.                                      pReq->GCBaseAddr, pReq->cbModule, pReq->cRegions, pReq->aRegions);
  2341. }
  2342.  
  2343. /**
  2344.  * Handles VMMDevReq_UnregisterSharedModule.
  2345.  *
  2346.  * @returns VBox status code that the guest should see.
  2347.  * @param   pThis           The VMMDev instance data.
  2348.  * @param   pReqHdr         The header of the request to handle.
  2349.  */
  2350. static int vmmdevReqHandler_UnregisterSharedModule(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2351. {
  2352.     /*
  2353.      * Basic input validation.
  2354.      */
  2355.     VMMDevSharedModuleUnregistrationRequest *pReq = (VMMDevSharedModuleUnregistrationRequest *)pReqHdr;
  2356.     AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleUnregistrationRequest),
  2357.                     ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2358.  
  2359.     AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
  2360.     AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
  2361.     int rc = RTStrValidateEncoding(pReq->szName);
  2362.     AssertRCReturn(rc, rc);
  2363.     rc = RTStrValidateEncoding(pReq->szVersion);
  2364.     AssertRCReturn(rc, rc);
  2365.  
  2366.     /*
  2367.      * Forward the request to the VMM.
  2368.      */
  2369.     return PGMR3SharedModuleUnregister(PDMDevHlpGetVM(pThis->pDevIns), pReq->szName, pReq->szVersion,
  2370.                                        pReq->GCBaseAddr, pReq->cbModule);
  2371. }
  2372.  
  2373. /**
  2374.  * Handles VMMDevReq_CheckSharedModules.
  2375.  *
  2376.  * @returns VBox status code that the guest should see.
  2377.  * @param   pThis           The VMMDev instance data.
  2378.  * @param   pReqHdr         The header of the request to handle.
  2379.  */
  2380. static int vmmdevReqHandler_CheckSharedModules(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2381. {
  2382.     VMMDevSharedModuleCheckRequest *pReq = (VMMDevSharedModuleCheckRequest *)pReqHdr;
  2383.     AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleCheckRequest),
  2384.                     ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2385.     return PGMR3SharedModuleCheckAll(PDMDevHlpGetVM(pThis->pDevIns));
  2386. }
  2387.  
  2388. /**
  2389.  * Handles VMMDevReq_GetPageSharingStatus.
  2390.  *
  2391.  * @returns VBox status code that the guest should see.
  2392.  * @param   pThis           The VMMDev instance data.
  2393.  * @param   pReqHdr         The header of the request to handle.
  2394.  */
  2395. static int vmmdevReqHandler_GetPageSharingStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2396. {
  2397.     VMMDevPageSharingStatusRequest *pReq = (VMMDevPageSharingStatusRequest *)pReqHdr;
  2398.     AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageSharingStatusRequest),
  2399.                     ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2400.  
  2401.     pReq->fEnabled = false;
  2402.     int rc = pThis->pDrv->pfnIsPageFusionEnabled(pThis->pDrv, &pReq->fEnabled);
  2403.     if (RT_FAILURE(rc))
  2404.         pReq->fEnabled = false;
  2405.     return VINF_SUCCESS;
  2406. }
  2407.  
  2408.  
  2409. /**
  2410.  * Handles VMMDevReq_DebugIsPageShared.
  2411.  *
  2412.  * @returns VBox status code that the guest should see.
  2413.  * @param   pThis           The VMMDev instance data.
  2414.  * @param   pReqHdr         The header of the request to handle.
  2415.  */
  2416. static int vmmdevReqHandler_DebugIsPageShared(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2417. {
  2418.     VMMDevPageIsSharedRequest *pReq = (VMMDevPageIsSharedRequest *)pReqHdr;
  2419.     AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageIsSharedRequest),
  2420.                     ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2421.  
  2422. # ifdef DEBUG
  2423.     return PGMR3SharedModuleGetPageState(PDMDevHlpGetVM(pThis->pDevIns), pReq->GCPtrPage, &pReq->fShared, &pReq->uPageFlags);
  2424. # else
  2425.     RT_NOREF1(pThis);
  2426.     return VERR_NOT_IMPLEMENTED;
  2427. # endif
  2428. }
  2429.  
  2430. #endif /* VBOX_WITH_PAGE_SHARING */
  2431.  
  2432.  
  2433. /**
  2434.  * Handles VMMDevReq_WriteCoreDumpe
  2435.  *
  2436.  * @returns VBox status code that the guest should see.
  2437.  * @param   pThis           The VMMDev instance data.
  2438.  * @param   pReqHdr         Pointer to the request header.
  2439.  */
  2440. static int vmmdevReqHandler_WriteCoreDump(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
  2441. {
  2442.     VMMDevReqWriteCoreDump *pReq = (VMMDevReqWriteCoreDump *)pReqHdr;
  2443.     AssertMsgReturn(pReq->header.size == sizeof(VMMDevReqWriteCoreDump), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
  2444.  
  2445.     /*
  2446.      * Only available if explicitly enabled by the user.
  2447.      */
  2448.     if (!pThis->fGuestCoreDumpEnabled)
  2449.         return VERR_ACCESS_DENIED;
  2450.  
  2451.     /*
  2452.      * User makes sure the directory exists before composing the path.
  2453.      */
  2454.     if (!RTDirExists(pThis->szGuestCoreDumpDir))
  2455.         return VERR_PATH_NOT_FOUND;
  2456.  
  2457.     char szCorePath[RTPATH_MAX];
  2458.     RTStrCopy(szCorePath, sizeof(szCorePath), pThis->szGuestCoreDumpDir);
  2459.     RTPathAppend(szCorePath, sizeof(szCorePath), "VBox.core");
  2460.  
  2461.     /*
  2462.      * Rotate existing cores based on number of additional cores to keep around.
  2463.      */
  2464.     if (pThis->cGuestCoreDumps > 0)
  2465.         for (int64_t i = pThis->cGuestCoreDumps - 1; i >= 0; i--)
  2466.         {
  2467.             char szFilePathOld[RTPATH_MAX];
  2468.             if (i == 0)
  2469.                 RTStrCopy(szFilePathOld, sizeof(szFilePathOld), szCorePath);
  2470.             else
  2471.                 RTStrPrintf(szFilePathOld, sizeof(szFilePathOld), "%s.%lld", szCorePath, i);
  2472.  
  2473.             char szFilePathNew[RTPATH_MAX];
  2474.             RTStrPrintf(szFilePathNew, sizeof(szFilePathNew), "%s.%lld", szCorePath, i + 1);
  2475.             int vrc = RTFileMove(szFilePathOld, szFilePathNew, RTFILEMOVE_FLAGS_REPLACE);
  2476.             if (vrc == VERR_FILE_NOT_FOUND)
  2477.                 RTFileDelete(szFilePathNew);
  2478.         }
  2479.  
  2480.     /*
  2481.      * Write the core file.
  2482.      */
  2483.     PUVM pUVM = PDMDevHlpGetUVM(pThis->pDevIns);
  2484.     return DBGFR3CoreWrite(pUVM, szCorePath, true /*fReplaceFile*/);
  2485. }
  2486.  
  2487.  
  2488. /**
  2489.  * Dispatch the request to the appropriate handler function.
  2490.  *
  2491.  * @returns Port I/O handler exit code.
  2492.  * @param   pThis           The VMM device instance data.
  2493.  * @param   pReqHdr         The request header (cached in host memory).
  2494.  * @param   GCPhysReqHdr    The guest physical address of the request (for
  2495.  *                          HGCM).
  2496.  * @param   pfDelayedUnlock Where to indicate whether the critical section exit
  2497.  *                          needs to be delayed till after the request has been
  2498.  *                          written back. This is a HGCM kludge, see critsect
  2499.  *                          work in hgcmCompletedWorker for more details.
  2500.  */
  2501. static int vmmdevReqDispatcher(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr, bool *pfDelayedUnlock)
  2502. {
  2503.     int rcRet = VINF_SUCCESS;
  2504.     *pfDelayedUnlock = false;
  2505.  
  2506.     switch (pReqHdr->requestType)
  2507.     {
  2508.         case VMMDevReq_ReportGuestInfo:
  2509.             pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo(pThis, pReqHdr);
  2510.             break;
  2511.  
  2512.         case VMMDevReq_ReportGuestInfo2:
  2513.             pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo2(pThis, pReqHdr);
  2514.             break;
  2515.  
  2516.         case VMMDevReq_ReportGuestStatus:
  2517.             pReqHdr->rc = vmmdevReqHandler_ReportGuestStatus(pThis, pReqHdr);
  2518.             break;
  2519.  
  2520.         case VMMDevReq_ReportGuestUserState:
  2521.             pReqHdr->rc = vmmdevReqHandler_ReportGuestUserState(pThis, pReqHdr);
  2522.             break;
  2523.  
  2524.         case VMMDevReq_ReportGuestCapabilities:
  2525.             pReqHdr->rc = vmmdevReqHandler_ReportGuestCapabilities(pThis, pReqHdr);
  2526.             break;
  2527.  
  2528.         case VMMDevReq_SetGuestCapabilities:
  2529.             pReqHdr->rc = vmmdevReqHandler_SetGuestCapabilities(pThis, pReqHdr);
  2530.             break;
  2531.  
  2532.         case VMMDevReq_WriteCoreDump:
  2533.             pReqHdr->rc = vmmdevReqHandler_WriteCoreDump(pThis, pReqHdr);
  2534.             break;
  2535.  
  2536.         case VMMDevReq_GetMouseStatus:
  2537.             pReqHdr->rc = vmmdevReqHandler_GetMouseStatus(pThis, pReqHdr);
  2538.             break;
  2539.  
  2540.         case VMMDevReq_SetMouseStatus:
  2541.             pReqHdr->rc = vmmdevReqHandler_SetMouseStatus(pThis, pReqHdr);
  2542.             break;
  2543.  
  2544.         case VMMDevReq_SetPointerShape:
  2545.             pReqHdr->rc = vmmdevReqHandler_SetPointerShape(pThis, pReqHdr);
  2546.             break;
  2547.  
  2548.         case VMMDevReq_GetHostTime:
  2549.             pReqHdr->rc = vmmdevReqHandler_GetHostTime(pThis, pReqHdr);
  2550.             break;
  2551.  
  2552.         case VMMDevReq_GetHypervisorInfo:
  2553.             pReqHdr->rc = vmmdevReqHandler_GetHypervisorInfo(pThis, pReqHdr);
  2554.             break;
  2555.  
  2556.         case VMMDevReq_SetHypervisorInfo:
  2557.             pReqHdr->rc = vmmdevReqHandler_SetHypervisorInfo(pThis, pReqHdr);
  2558.             break;
  2559.  
  2560.         case VMMDevReq_RegisterPatchMemory:
  2561.             pReqHdr->rc = vmmdevReqHandler_RegisterPatchMemory(pThis, pReqHdr);
  2562.             break;
  2563.  
  2564.         case VMMDevReq_DeregisterPatchMemory:
  2565.             pReqHdr->rc = vmmdevReqHandler_DeregisterPatchMemory(pThis, pReqHdr);
  2566.             break;
  2567.  
  2568.         case VMMDevReq_SetPowerStatus:
  2569.         {
  2570.             int rc = pReqHdr->rc = vmmdevReqHandler_SetPowerStatus(pThis, pReqHdr);
  2571.             if (rc != VINF_SUCCESS && RT_SUCCESS(rc))
  2572.                 rcRet = rc;
  2573.             break;
  2574.         }
  2575.  
  2576.         case VMMDevReq_GetDisplayChangeRequest:
  2577.             pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest(pThis, pReqHdr);
  2578.             break;
  2579.  
  2580.         case VMMDevReq_GetDisplayChangeRequest2:
  2581.             pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest2(pThis, pReqHdr);
  2582.             break;
  2583.  
  2584.         case VMMDevReq_GetDisplayChangeRequestEx:
  2585.             pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequestEx(pThis, pReqHdr);
  2586.             break;
  2587.  
  2588.         case VMMDevReq_VideoModeSupported:
  2589.             pReqHdr->rc = vmmdevReqHandler_VideoModeSupported(pThis, pReqHdr);
  2590.             break;
  2591.  
  2592.         case VMMDevReq_VideoModeSupported2:
  2593.             pReqHdr->rc = vmmdevReqHandler_VideoModeSupported2(pThis, pReqHdr);
  2594.             break;
  2595.  
  2596.         case VMMDevReq_GetHeightReduction:
  2597.             pReqHdr->rc = vmmdevReqHandler_GetHeightReduction(pThis, pReqHdr);
  2598.             break;
  2599.  
  2600.         case VMMDevReq_AcknowledgeEvents:
  2601.             pReqHdr->rc = vmmdevReqHandler_AcknowledgeEvents(pThis, pReqHdr);
  2602.             break;
  2603.  
  2604.         case VMMDevReq_CtlGuestFilterMask:
  2605.             pReqHdr->rc = vmmdevReqHandler_CtlGuestFilterMask(pThis, pReqHdr);
  2606.             break;
  2607.  
  2608. #ifdef VBOX_WITH_HGCM
  2609.         case VMMDevReq_HGCMConnect:
  2610.             pReqHdr->rc = vmmdevReqHandler_HGCMConnect(pThis, pReqHdr, GCPhysReqHdr);
  2611.             *pfDelayedUnlock = true;
  2612.             break;
  2613.  
  2614.         case VMMDevReq_HGCMDisconnect:
  2615.             pReqHdr->rc = vmmdevReqHandler_HGCMDisconnect(pThis, pReqHdr, GCPhysReqHdr);
  2616.             *pfDelayedUnlock = true;
  2617.             break;
  2618.  
  2619. # ifdef VBOX_WITH_64_BITS_GUESTS
  2620.         case VMMDevReq_HGCMCall32:
  2621.         case VMMDevReq_HGCMCall64:
  2622. # else
  2623.         case VMMDevReq_HGCMCall:
  2624. # endif /* VBOX_WITH_64_BITS_GUESTS */
  2625.             pReqHdr->rc = vmmdevReqHandler_HGCMCall(pThis, pReqHdr, GCPhysReqHdr);
  2626.             *pfDelayedUnlock = true;
  2627.             break;
  2628.  
  2629.         case VMMDevReq_HGCMCancel:
  2630.             pReqHdr->rc = vmmdevReqHandler_HGCMCancel(pThis, pReqHdr, GCPhysReqHdr);
  2631.             *pfDelayedUnlock = true;
  2632.             break;
  2633.  
  2634.         case VMMDevReq_HGCMCancel2:
  2635.             pReqHdr->rc = vmmdevReqHandler_HGCMCancel2(pThis, pReqHdr);
  2636.             break;
  2637. #endif /* VBOX_WITH_HGCM */
  2638.  
  2639.         case VMMDevReq_VideoAccelEnable:
  2640.             pReqHdr->rc = vmmdevReqHandler_VideoAccelEnable(pThis, pReqHdr);
  2641.             break;
  2642.  
  2643.         case VMMDevReq_VideoAccelFlush:
  2644.             pReqHdr->rc = vmmdevReqHandler_VideoAccelFlush(pThis, pReqHdr);
  2645.             break;
  2646.  
  2647.         case VMMDevReq_VideoSetVisibleRegion:
  2648.             pReqHdr->rc = vmmdevReqHandler_VideoSetVisibleRegion(pThis, pReqHdr);
  2649.             break;
  2650.  
  2651.         case VMMDevReq_GetSeamlessChangeRequest:
  2652.             pReqHdr->rc = vmmdevReqHandler_GetSeamlessChangeRequest(pThis, pReqHdr);
  2653.             break;
  2654.  
  2655.         case VMMDevReq_GetVRDPChangeRequest:
  2656.             pReqHdr->rc = vmmdevReqHandler_GetVRDPChangeRequest(pThis, pReqHdr);
  2657.             break;
  2658.  
  2659.         case VMMDevReq_GetMemBalloonChangeRequest:
  2660.             pReqHdr->rc = vmmdevReqHandler_GetMemBalloonChangeRequest(pThis, pReqHdr);
  2661.             break;
  2662.  
  2663.         case VMMDevReq_ChangeMemBalloon:
  2664.             pReqHdr->rc = vmmdevReqHandler_ChangeMemBalloon(pThis, pReqHdr);
  2665.             break;
  2666.  
  2667.         case VMMDevReq_GetStatisticsChangeRequest:
  2668.             pReqHdr->rc = vmmdevReqHandler_GetStatisticsChangeRequest(pThis, pReqHdr);
  2669.             break;
  2670.  
  2671.         case VMMDevReq_ReportGuestStats:
  2672.             pReqHdr->rc = vmmdevReqHandler_ReportGuestStats(pThis, pReqHdr);
  2673.             break;
  2674.  
  2675.         case VMMDevReq_QueryCredentials:
  2676.             pReqHdr->rc = vmmdevReqHandler_QueryCredentials(pThis, pReqHdr);
  2677.             break;
  2678.  
  2679.         case VMMDevReq_ReportCredentialsJudgement:
  2680.             pReqHdr->rc = vmmdevReqHandler_ReportCredentialsJudgement(pThis, pReqHdr);
  2681.             break;
  2682.  
  2683.         case VMMDevReq_GetHostVersion:
  2684.             pReqHdr->rc = vmmdevReqHandler_GetHostVersion(pReqHdr);
  2685.             break;
  2686.  
  2687.         case VMMDevReq_GetCpuHotPlugRequest:
  2688.             pReqHdr->rc = vmmdevReqHandler_GetCpuHotPlugRequest(pThis, pReqHdr);
  2689.             break;
  2690.  
  2691.         case VMMDevReq_SetCpuHotPlugStatus:
  2692.             pReqHdr->rc = vmmdevReqHandler_SetCpuHotPlugStatus(pThis, pReqHdr);
  2693.             break;
  2694.  
  2695. #ifdef VBOX_WITH_PAGE_SHARING
  2696.         case VMMDevReq_RegisterSharedModule:
  2697.             pReqHdr->rc = vmmdevReqHandler_RegisterSharedModule(pThis, pReqHdr);
  2698.             break;
  2699.  
  2700.         case VMMDevReq_UnregisterSharedModule:
  2701.             pReqHdr->rc = vmmdevReqHandler_UnregisterSharedModule(pThis, pReqHdr);
  2702.             break;
  2703.  
  2704.         case VMMDevReq_CheckSharedModules:
  2705.             pReqHdr->rc = vmmdevReqHandler_CheckSharedModules(pThis, pReqHdr);
  2706.             break;
  2707.  
  2708.         case VMMDevReq_GetPageSharingStatus:
  2709.             pReqHdr->rc = vmmdevReqHandler_GetPageSharingStatus(pThis, pReqHdr);
  2710.             break;
  2711.  
  2712.         case VMMDevReq_DebugIsPageShared:
  2713.             pReqHdr->rc = vmmdevReqHandler_DebugIsPageShared(pThis, pReqHdr);
  2714.             break;
  2715.  
  2716. #endif /* VBOX_WITH_PAGE_SHARING */
  2717.  
  2718. #ifdef DEBUG
  2719.         case VMMDevReq_LogString:
  2720.             pReqHdr->rc = vmmdevReqHandler_LogString(pReqHdr);
  2721.             break;
  2722. #endif
  2723.  
  2724.         case VMMDevReq_GetSessionId:
  2725.             pReqHdr->rc = vmmdevReqHandler_GetSessionId(pThis, pReqHdr);
  2726.             break;
  2727.  
  2728.         /*
  2729.          * Guest wants to give up a timeslice.
  2730.          * Note! This was only ever used by experimental GAs!
  2731.          */
  2732.         /** @todo maybe we could just remove this? */
  2733.         case VMMDevReq_Idle:
  2734.         {
  2735.             /* just return to EMT telling it that we want to halt */
  2736.             rcRet = VINF_EM_HALT;
  2737.             break;
  2738.         }
  2739.  
  2740.         case VMMDevReq_GuestHeartbeat:
  2741.             pReqHdr->rc = vmmDevReqHandler_GuestHeartbeat(pThis);
  2742.             break;
  2743.  
  2744.         case VMMDevReq_HeartbeatConfigure:
  2745.             pReqHdr->rc = vmmDevReqHandler_HeartbeatConfigure(pThis, pReqHdr);
  2746.             break;
  2747.  
  2748.         default:
  2749.         {
  2750.             pReqHdr->rc = VERR_NOT_IMPLEMENTED;
  2751.             Log(("VMMDev unknown request type %d\n", pReqHdr->requestType));
  2752.             break;
  2753.         }
  2754.     }
  2755.     return rcRet;
  2756. }
  2757.  
  2758.  
  2759. /**
  2760.  * @callback_method_impl{FNIOMIOPORTOUT, Port I/O Handler for the generic
  2761.  *                      request interface.}
  2762.  */
  2763. static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
  2764. {
  2765.     RT_NOREF2(Port, cb);
  2766.     PVMMDEV pThis = (VMMDevState*)pvUser;
  2767.  
  2768.     /*
  2769.      * The caller has passed the guest context physical address of the request
  2770.      * structure. We'll copy all of it into a heap buffer eventually, but we
  2771.      * will have to start off with the header.
  2772.      */
  2773.     VMMDevRequestHeader requestHeader;
  2774.     RT_ZERO(requestHeader);
  2775.     PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
  2776.  
  2777.     /* The structure size must be greater or equal to the header size. */
  2778.     if (requestHeader.size < sizeof(VMMDevRequestHeader))
  2779.     {
  2780.         Log(("VMMDev request header size too small! size = %d\n", requestHeader.size));
  2781.         return VINF_SUCCESS;
  2782.     }
  2783.  
  2784.     /* Check the version of the header structure. */
  2785.     if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
  2786.     {
  2787.         Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
  2788.         return VINF_SUCCESS;
  2789.     }
  2790.  
  2791.     Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
  2792.  
  2793.     int                  rcRet          = VINF_SUCCESS;
  2794.     bool                 fDelayedUnlock = false;
  2795.     VMMDevRequestHeader *pRequestHeader = NULL;
  2796.  
  2797.     /* Check that is doesn't exceed the max packet size. */
  2798.     if (requestHeader.size <= VMMDEV_MAX_VMMDEVREQ_SIZE)
  2799.     {
  2800.         /*
  2801.          * We require the GAs to report it's information before we let it have
  2802.          * access to all the functions.  The VMMDevReq_ReportGuestInfo request
  2803.          * is the one which unlocks the access.  Newer additions will first
  2804.          * issue VMMDevReq_ReportGuestInfo2, older ones doesn't know this one.
  2805.          * Two exceptions: VMMDevReq_GetHostVersion and VMMDevReq_WriteCoreDump.
  2806.          */
  2807.         if (   pThis->fu32AdditionsOk
  2808.             || requestHeader.requestType == VMMDevReq_ReportGuestInfo2
  2809.             || requestHeader.requestType == VMMDevReq_ReportGuestInfo
  2810.             || requestHeader.requestType == VMMDevReq_WriteCoreDump
  2811.             || requestHeader.requestType == VMMDevReq_GetHostVersion
  2812.            )
  2813.         {
  2814.             /*
  2815.              * The request looks fine. Allocate a heap block for it, read the
  2816.              * entire package from guest memory and feed it to the dispatcher.
  2817.              */
  2818.             pRequestHeader = (VMMDevRequestHeader *)RTMemAlloc(requestHeader.size);
  2819.             if (pRequestHeader)
  2820.             {
  2821.                 memcpy(pRequestHeader, &requestHeader, sizeof(VMMDevRequestHeader));
  2822.                 size_t cbLeft = requestHeader.size - sizeof(VMMDevRequestHeader);
  2823.                 if (cbLeft)
  2824.                     PDMDevHlpPhysRead(pDevIns,
  2825.                                       (RTGCPHYS)u32             + sizeof(VMMDevRequestHeader),
  2826.                                       (uint8_t *)pRequestHeader + sizeof(VMMDevRequestHeader),
  2827.                                       cbLeft);
  2828.  
  2829.                 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  2830.                 rcRet = vmmdevReqDispatcher(pThis, pRequestHeader, u32, &fDelayedUnlock);
  2831.                 if (!fDelayedUnlock)
  2832.                     PDMCritSectLeave(&pThis->CritSect);
  2833.             }
  2834.             else
  2835.             {
  2836.                 Log(("VMMDev: RTMemAlloc failed!\n"));
  2837.                 requestHeader.rc = VERR_NO_MEMORY;
  2838.             }
  2839.         }
  2840.         else
  2841.         {
  2842.             LogRelMax(10, ("VMMDev: Guest has not yet reported to us -- refusing operation of request #%d\n",
  2843.                            requestHeader.requestType));
  2844.             requestHeader.rc = VERR_NOT_SUPPORTED;
  2845.         }
  2846.     }
  2847.     else
  2848.     {
  2849.         LogRelMax(50, ("VMMDev: Request packet too big (%x), refusing operation\n", requestHeader.size));
  2850.         requestHeader.rc = VERR_NOT_SUPPORTED;
  2851.     }
  2852.  
  2853.     /*
  2854.      * Write the result back to guest memory
  2855.      */
  2856.     if (pRequestHeader)
  2857.     {
  2858.         PDMDevHlpPhysWrite(pDevIns, u32, pRequestHeader, pRequestHeader->size);
  2859.         if (fDelayedUnlock)
  2860.             PDMCritSectLeave(&pThis->CritSect);
  2861.         RTMemFree(pRequestHeader);
  2862.     }
  2863.     else
  2864.     {
  2865.         /* early error case; write back header only */
  2866.         PDMDevHlpPhysWrite(pDevIns, u32, &requestHeader, sizeof(requestHeader));
  2867.         Assert(!fDelayedUnlock);
  2868.     }
  2869.  
  2870.     return rcRet;
  2871. }
  2872.  
  2873.  
  2874. /* -=-=-=-=-=- PCI Device -=-=-=-=-=- */
  2875.  
  2876.  
  2877. /**
  2878.  * @callback_method_impl{FNPCIIOREGIONMAP,MMIO/MMIO2 regions}
  2879.  */
  2880. static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
  2881.                                               RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
  2882. {
  2883.     RT_NOREF1(cb);
  2884.     LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
  2885.     PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
  2886.     int rc;
  2887.  
  2888.     if (iRegion == 1)
  2889.     {
  2890.         AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM, VERR_INTERNAL_ERROR);
  2891.         Assert(pThis->pVMMDevRAMR3 != NULL);
  2892.         if (GCPhysAddress != NIL_RTGCPHYS)
  2893.         {
  2894.             /*
  2895.              * Map the MMIO2 memory.
  2896.              */
  2897.             pThis->GCPhysVMMDevRAM = GCPhysAddress;
  2898.             Assert(pThis->GCPhysVMMDevRAM == GCPhysAddress);
  2899.             rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
  2900.         }
  2901.         else
  2902.         {
  2903.             /*
  2904.              * It is about to be unmapped, just clean up.
  2905.              */
  2906.             pThis->GCPhysVMMDevRAM = NIL_RTGCPHYS32;
  2907.             rc = VINF_SUCCESS;
  2908.         }
  2909.     }
  2910.     else if (iRegion == 2)
  2911.     {
  2912.         AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
  2913.         Assert(pThis->pVMMDevHeapR3 != NULL);
  2914.         if (GCPhysAddress != NIL_RTGCPHYS)
  2915.         {
  2916.             /*
  2917.              * Map the MMIO2 memory.
  2918.              */
  2919.             pThis->GCPhysVMMDevHeap = GCPhysAddress;
  2920.             Assert(pThis->GCPhysVMMDevHeap == GCPhysAddress);
  2921.             rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
  2922.             if (RT_SUCCESS(rc))
  2923.                 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, GCPhysAddress, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
  2924.         }
  2925.         else
  2926.         {
  2927.             /*
  2928.              * It is about to be unmapped, just clean up.
  2929.              */
  2930.             PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
  2931.             pThis->GCPhysVMMDevHeap = NIL_RTGCPHYS32;
  2932.             rc = VINF_SUCCESS;
  2933.         }
  2934.     }
  2935.     else
  2936.     {
  2937.         AssertMsgFailed(("%d\n", iRegion));
  2938.         rc = VERR_INVALID_PARAMETER;
  2939.     }
  2940.  
  2941.     return rc;
  2942. }
  2943.  
  2944.  
  2945. /**
  2946.  * @callback_method_impl{FNPCIIOREGIONMAP,I/O Port Region}
  2947.  */
  2948. static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
  2949.                                                RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
  2950. {
  2951.     RT_NOREF3(iRegion, cb, enmType);
  2952.     PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
  2953.  
  2954.     Assert(enmType == PCI_ADDRESS_SPACE_IO);
  2955.     Assert(iRegion == 0);
  2956.     AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
  2957.  
  2958.     /*
  2959.      * Register our port IO handlers.
  2960.      */
  2961.     int rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
  2962.                                      pThis, vmmdevRequestHandler, NULL, NULL, NULL, "VMMDev Request Handler");
  2963.     AssertRC(rc);
  2964.     return rc;
  2965. }
  2966.  
  2967.  
  2968.  
  2969. /* -=-=-=-=-=- Backdoor Logging and Time Sync. -=-=-=-=-=- */
  2970.  
  2971. /**
  2972.  * @callback_method_impl{FNIOMIOPORTOUT, Backdoor Logging.}
  2973.  */
  2974. static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
  2975. {
  2976.     RT_NOREF1(pvUser);
  2977.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
  2978.  
  2979.     if (!pThis->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
  2980.     {
  2981.  
  2982.         /* The raw version. */
  2983.         switch (u32)
  2984.         {
  2985.             case '\r': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
  2986.             case '\n': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
  2987.             case '\t': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
  2988.             default:   LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: %c (%02x)\n", u32, u32)); break;
  2989.         }
  2990.  
  2991.         /* The readable, buffered version. */
  2992.         if (u32 == '\n' || u32 == '\r')
  2993.         {
  2994.             pThis->szMsg[pThis->iMsg] = '\0';
  2995.             if (pThis->iMsg)
  2996.                 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %s\n", pThis->szMsg));
  2997.             pThis->iMsg = 0;
  2998.         }
  2999.         else
  3000.         {
  3001.             if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
  3002.             {
  3003.                 pThis->szMsg[pThis->iMsg] = '\0';
  3004.                 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %s\n", pThis->szMsg));
  3005.                 pThis->iMsg = 0;
  3006.             }
  3007.             pThis->szMsg[pThis->iMsg] = (char )u32;
  3008.             pThis->szMsg[++pThis->iMsg] = '\0';
  3009.         }
  3010.     }
  3011.     return VINF_SUCCESS;
  3012. }
  3013.  
  3014. #ifdef VMMDEV_WITH_ALT_TIMESYNC
  3015.  
  3016. /**
  3017.  * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
  3018.  */
  3019. static DECLCALLBACK(int) vmmdevAltTimeSyncWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
  3020. {
  3021.     RT_NOREF2(pvUser, Port);
  3022.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
  3023.     if (cb == 4)
  3024.     {
  3025.         /* Selects high (0) or low (1) DWORD. The high has to be read first. */
  3026.         switch (u32)
  3027.         {
  3028.             case 0:
  3029.                 pThis->fTimesyncBackdoorLo = false;
  3030.                 break;
  3031.             case 1:
  3032.                 pThis->fTimesyncBackdoorLo = true;
  3033.                 break;
  3034.             default:
  3035.                 Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
  3036.                 break;
  3037.         }
  3038.     }
  3039.     else
  3040.         Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
  3041.     return VINF_SUCCESS;
  3042. }
  3043.  
  3044. /**
  3045.  * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
  3046.  */
  3047. static DECLCALLBACK(int) vmmdevAltTimeSyncRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
  3048. {
  3049.     RT_NOREF2(pvUser, Port);
  3050.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
  3051.     int     rc;
  3052.     if (cb == 4)
  3053.     {
  3054.         if (pThis->fTimesyncBackdoorLo)
  3055.             *pu32 = (uint32_t)pThis->hostTime;
  3056.         else
  3057.         {
  3058.             /* Reading the high dword gets and saves the current time. */
  3059.             RTTIMESPEC Now;
  3060.             pThis->hostTime = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &Now));
  3061.             *pu32 = (uint32_t)(pThis->hostTime >> 32);
  3062.         }
  3063.         rc = VINF_SUCCESS;
  3064.     }
  3065.     else
  3066.     {
  3067.         Log(("vmmdevAltTimeSyncRead: Invalid access cb=%#x\n", cb));
  3068.         rc = VERR_IOM_IOPORT_UNUSED;
  3069.     }
  3070.     return rc;
  3071. }
  3072.  
  3073. #endif /* VMMDEV_WITH_ALT_TIMESYNC */
  3074.  
  3075.  
  3076. /* -=-=-=-=-=- IBase -=-=-=-=-=- */
  3077.  
  3078. /**
  3079.  * @interface_method_impl{PDMIBASE,pfnQueryInterface}
  3080.  */
  3081. static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
  3082. {
  3083.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IBase);
  3084.  
  3085.     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
  3086.     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThis->IPort);
  3087. #ifdef VBOX_WITH_HGCM
  3088.     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMPORT, &pThis->IHGCMPort);
  3089. #endif
  3090.     /* Currently only for shared folders. */
  3091.     PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->SharedFolders.ILeds);
  3092.     return NULL;
  3093. }
  3094.  
  3095.  
  3096. /* -=-=-=-=-=- ILeds -=-=-=-=-=- */
  3097.  
  3098. /**
  3099.  * Gets the pointer to the status LED of a unit.
  3100.  *
  3101.  * @returns VBox status code.
  3102.  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
  3103.  * @param   iLUN            The unit which status LED we desire.
  3104.  * @param   ppLed           Where to store the LED pointer.
  3105.  */
  3106. static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
  3107. {
  3108.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, SharedFolders.ILeds);
  3109.     if (iLUN == 0) /* LUN 0 is shared folders */
  3110.     {
  3111.         *ppLed = &pThis->SharedFolders.Led;
  3112.         return VINF_SUCCESS;
  3113.     }
  3114.     return VERR_PDM_LUN_NOT_FOUND;
  3115. }
  3116.  
  3117.  
  3118. /* -=-=-=-=-=- PDMIVMMDEVPORT (VMMDEV::IPort) -=-=-=-=-=- */
  3119.  
  3120. /**
  3121.  * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryAbsoluteMouse}
  3122.  */
  3123. static DECLCALLBACK(int) vmmdevIPort_QueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)
  3124. {
  3125.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3126.  
  3127.     /** @todo at the first sign of trouble in this area, just enter the critsect.
  3128.      * As indicated by the comment below, the atomic reads serves no real purpose
  3129.      * here since we can assume cache coherency protocoles and int32_t alignment
  3130.      * rules making sure we won't see a halfwritten value. */
  3131.     if (pxAbs)
  3132.         *pxAbs = ASMAtomicReadS32(&pThis->mouseXAbs); /* why the atomic read? */
  3133.     if (pyAbs)
  3134.         *pyAbs = ASMAtomicReadS32(&pThis->mouseYAbs);
  3135.  
  3136.     return VINF_SUCCESS;
  3137. }
  3138.  
  3139. /**
  3140.  * @interface_method_impl{PDMIVMMDEVPORT,pfnSetAbsoluteMouse}
  3141.  */
  3142. static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs)
  3143. {
  3144.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3145.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3146.  
  3147.     if (   pThis->mouseXAbs != xAbs
  3148.         || pThis->mouseYAbs != yAbs)
  3149.     {
  3150.         Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d\n", xAbs, yAbs));
  3151.         pThis->mouseXAbs = xAbs;
  3152.         pThis->mouseYAbs = yAbs;
  3153.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
  3154.     }
  3155.  
  3156.     PDMCritSectLeave(&pThis->CritSect);
  3157.     return VINF_SUCCESS;
  3158. }
  3159.  
  3160. /**
  3161.  * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryMouseCapabilities}
  3162.  */
  3163. static DECLCALLBACK(int) vmmdevIPort_QueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)
  3164. {
  3165.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3166.     AssertPtrReturn(pfCapabilities, VERR_INVALID_PARAMETER);
  3167.  
  3168.     *pfCapabilities = pThis->mouseCapabilities;
  3169.     return VINF_SUCCESS;
  3170. }
  3171.  
  3172. /**
  3173.  * @interface_method_impl{PDMIVMMDEVPORT,pfnUpdateMouseCapabilities}
  3174.  */
  3175. static DECLCALLBACK(int)
  3176. vmmdevIPort_UpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)
  3177. {
  3178.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3179.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3180.  
  3181.     uint32_t fOldCaps = pThis->mouseCapabilities;
  3182.     pThis->mouseCapabilities &= ~(fCapsRemoved & VMMDEV_MOUSE_HOST_MASK);
  3183.     pThis->mouseCapabilities |= (fCapsAdded & VMMDEV_MOUSE_HOST_MASK)
  3184.                               | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
  3185.     bool fNotify = fOldCaps != pThis->mouseCapabilities;
  3186.  
  3187.     LogRelFlow(("VMMDev: vmmdevIPort_UpdateMouseCapabilities: fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify=%RTbool\n", fCapsAdded,
  3188.                 fCapsRemoved, fNotify));
  3189.  
  3190.     if (fNotify)
  3191.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
  3192.  
  3193.     PDMCritSectLeave(&pThis->CritSect);
  3194.     return VINF_SUCCESS;
  3195. }
  3196.  
  3197. /**
  3198.  * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestDisplayChange}
  3199.  */
  3200. static DECLCALLBACK(int)
  3201. vmmdevIPort_RequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t cx, uint32_t cy, uint32_t cBits, uint32_t idxDisplay,
  3202.                                  int32_t xOrigin, int32_t yOrigin, bool fEnabled, bool fChangeOrigin)
  3203. {
  3204.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3205.  
  3206.     if (idxDisplay >= RT_ELEMENTS(pThis->displayChangeData.aRequests))
  3207.         return VERR_INVALID_PARAMETER;
  3208.  
  3209.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3210.  
  3211.     DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[idxDisplay];
  3212.  
  3213.     /* Verify that the new resolution is different and that guest does not yet know about it. */
  3214.     bool fSameResolution = (!cx    || pRequest->lastReadDisplayChangeRequest.xres == cx)
  3215.                         && (!cy    || pRequest->lastReadDisplayChangeRequest.yres == cy)
  3216.                         && (!cBits || pRequest->lastReadDisplayChangeRequest.bpp  == cBits)
  3217.                         && pRequest->lastReadDisplayChangeRequest.xOrigin  == xOrigin
  3218.                         && pRequest->lastReadDisplayChangeRequest.yOrigin  == yOrigin
  3219.                         && pRequest->lastReadDisplayChangeRequest.fEnabled == fEnabled
  3220.                         && pRequest->lastReadDisplayChangeRequest.display  == idxDisplay;
  3221.  
  3222.     if (!cx && !cy && !cBits)
  3223.     {
  3224.         /* Special case of reset video mode. */
  3225.         fSameResolution = false;
  3226.     }
  3227.  
  3228.     Log3(("vmmdevIPort_RequestDisplayChange: same=%d. new: cx=%d, cy=%d, cBits=%d, idxDisplay=%d.\
  3229.          old: cx=%d, cy=%d, cBits=%d, idxDisplay=%d. \n \
  3230.          ,OriginX = %d , OriginY=%d, Enabled=%d, ChangeOrigin=%d\n",
  3231.           fSameResolution, cx, cy, cBits, idxDisplay, pRequest->lastReadDisplayChangeRequest.xres,
  3232.           pRequest->lastReadDisplayChangeRequest.yres, pRequest->lastReadDisplayChangeRequest.bpp,
  3233.           pRequest->lastReadDisplayChangeRequest.display,
  3234.           xOrigin, yOrigin, fEnabled, fChangeOrigin));
  3235.  
  3236.     /* we could validate the information here but hey, the guest can do that as well! */
  3237.     pRequest->displayChangeRequest.xres          = cx;
  3238.     pRequest->displayChangeRequest.yres          = cy;
  3239.     pRequest->displayChangeRequest.bpp           = cBits;
  3240.     pRequest->displayChangeRequest.display       = idxDisplay;
  3241.     pRequest->displayChangeRequest.xOrigin       = xOrigin;
  3242.     pRequest->displayChangeRequest.yOrigin       = yOrigin;
  3243.     pRequest->displayChangeRequest.fEnabled      = fEnabled;
  3244.     pRequest->displayChangeRequest.fChangeOrigin = fChangeOrigin;
  3245.  
  3246.     pRequest->fPending = !fSameResolution;
  3247.  
  3248.     if (!fSameResolution)
  3249.     {
  3250.         LogRel(("VMMDev: SetVideoModeHint: Got a video mode hint (%dx%dx%d)@(%dx%d),(%d;%d) at %d\n",
  3251.                 cx, cy, cBits, xOrigin, yOrigin, fEnabled, fChangeOrigin, idxDisplay));
  3252.  
  3253.         /* IRQ so the guest knows what's going on */
  3254.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
  3255.     }
  3256.  
  3257.     PDMCritSectLeave(&pThis->CritSect);
  3258.     return VINF_SUCCESS;
  3259. }
  3260.  
  3261. /**
  3262.  * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestSeamlessChange}
  3263.  */
  3264. static DECLCALLBACK(int) vmmdevIPort_RequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
  3265. {
  3266.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3267.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3268.  
  3269.     /* Verify that the new resolution is different and that guest does not yet know about it. */
  3270.     bool fSameMode = (pThis->fLastSeamlessEnabled == fEnabled);
  3271.  
  3272.     Log(("vmmdevIPort_RequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
  3273.  
  3274.     if (!fSameMode)
  3275.     {
  3276.         /* we could validate the information here but hey, the guest can do that as well! */
  3277.         pThis->fSeamlessEnabled = fEnabled;
  3278.  
  3279.         /* IRQ so the guest knows what's going on */
  3280.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
  3281.     }
  3282.  
  3283.     PDMCritSectLeave(&pThis->CritSect);
  3284.     return VINF_SUCCESS;
  3285. }
  3286.  
  3287. /**
  3288.  * @interface_method_impl{PDMIVMMDEVPORT,pfnSetMemoryBalloon}
  3289.  */
  3290. static DECLCALLBACK(int) vmmdevIPort_SetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)
  3291. {
  3292.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3293.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3294.  
  3295.     /* Verify that the new resolution is different and that guest does not yet know about it. */
  3296.     Log(("vmmdevIPort_SetMemoryBalloon: old=%u new=%u\n", pThis->cMbMemoryBalloonLast, cMbBalloon));
  3297.     if (pThis->cMbMemoryBalloonLast != cMbBalloon)
  3298.     {
  3299.         /* we could validate the information here but hey, the guest can do that as well! */
  3300.         pThis->cMbMemoryBalloon = cMbBalloon;
  3301.  
  3302.         /* IRQ so the guest knows what's going on */
  3303.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
  3304.     }
  3305.  
  3306.     PDMCritSectLeave(&pThis->CritSect);
  3307.     return VINF_SUCCESS;
  3308. }
  3309.  
  3310. /**
  3311.  * @interface_method_impl{PDMIVMMDEVPORT,pfnVRDPChange}
  3312.  */
  3313. static DECLCALLBACK(int) vmmdevIPort_VRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)
  3314. {
  3315.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3316.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3317.  
  3318.     bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
  3319.  
  3320.     Log(("vmmdevIPort_VRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
  3321.  
  3322.     if (!fSame)
  3323.     {
  3324.         pThis->fVRDPEnabled = fVRDPEnabled;
  3325.         pThis->uVRDPExperienceLevel = uVRDPExperienceLevel;
  3326.  
  3327.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_VRDP);
  3328.     }
  3329.  
  3330.     PDMCritSectLeave(&pThis->CritSect);
  3331.     return VINF_SUCCESS;
  3332. }
  3333.  
  3334. /**
  3335.  * @interface_method_impl{PDMIVMMDEVPORT,pfnSetStatisticsInterval}
  3336.  */
  3337. static DECLCALLBACK(int) vmmdevIPort_SetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)
  3338. {
  3339.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3340.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3341.  
  3342.     /* Verify that the new resolution is different and that guest does not yet know about it. */
  3343.     bool fSame = (pThis->u32LastStatIntervalSize == cSecsStatInterval);
  3344.  
  3345.     Log(("vmmdevIPort_SetStatisticsInterval: old=%d. new=%d\n", pThis->u32LastStatIntervalSize, cSecsStatInterval));
  3346.  
  3347.     if (!fSame)
  3348.     {
  3349.         /* we could validate the information here but hey, the guest can do that as well! */
  3350.         pThis->u32StatIntervalSize = cSecsStatInterval;
  3351.  
  3352.         /* IRQ so the guest knows what's going on */
  3353.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
  3354.     }
  3355.  
  3356.     PDMCritSectLeave(&pThis->CritSect);
  3357.     return VINF_SUCCESS;
  3358. }
  3359.  
  3360. /**
  3361.  * @interface_method_impl{PDMIVMMDEVPORT,pfnSetCredentials}
  3362.  */
  3363. static DECLCALLBACK(int) vmmdevIPort_SetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
  3364.                                                     const char *pszPassword, const char *pszDomain, uint32_t fFlags)
  3365. {
  3366.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3367.     AssertReturn(fFlags & (VMMDEV_SETCREDENTIALS_GUESTLOGON | VMMDEV_SETCREDENTIALS_JUDGE), VERR_INVALID_PARAMETER);
  3368.  
  3369.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3370.  
  3371.     /*
  3372.      * Logon mode
  3373.      */
  3374.     if (fFlags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
  3375.     {
  3376.         /* memorize the data */
  3377.         strcpy(pThis->pCredentials->Logon.szUserName, pszUsername);
  3378.         strcpy(pThis->pCredentials->Logon.szPassword, pszPassword);
  3379.         strcpy(pThis->pCredentials->Logon.szDomain,   pszDomain);
  3380.         pThis->pCredentials->Logon.fAllowInteractiveLogon = !(fFlags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
  3381.     }
  3382.     /*
  3383.      * Credentials verification mode?
  3384.      */
  3385.     else
  3386.     {
  3387.         /* memorize the data */
  3388.         strcpy(pThis->pCredentials->Judge.szUserName, pszUsername);
  3389.         strcpy(pThis->pCredentials->Judge.szPassword, pszPassword);
  3390.         strcpy(pThis->pCredentials->Judge.szDomain,   pszDomain);
  3391.  
  3392.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_JUDGE_CREDENTIALS);
  3393.     }
  3394.  
  3395.     PDMCritSectLeave(&pThis->CritSect);
  3396.     return VINF_SUCCESS;
  3397. }
  3398.  
  3399. /**
  3400.  * @interface_method_impl{PDMIVMMDEVPORT,pfnVBVAChange}
  3401.  *
  3402.  * Notification from the Display.  Especially useful when acceleration is
  3403.  * disabled after a video mode change.
  3404.  */
  3405. static DECLCALLBACK(void) vmmdevIPort_VBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
  3406. {
  3407.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3408.     Log(("vmmdevIPort_VBVAChange: fEnabled = %d\n", fEnabled));
  3409.  
  3410.     /* Only used by saved state, which I guess is why we don't bother with locking here. */
  3411.     pThis->u32VideoAccelEnabled = fEnabled;
  3412. }
  3413.  
  3414. /**
  3415.  * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotUnplug}
  3416.  */
  3417. static DECLCALLBACK(int) vmmdevIPort_CpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
  3418. {
  3419.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3420.     int     rc    = VINF_SUCCESS;
  3421.  
  3422.     Log(("vmmdevIPort_CpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
  3423.  
  3424.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3425.  
  3426.     if (pThis->fCpuHotPlugEventsEnabled)
  3427.     {
  3428.         pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
  3429.         pThis->idCpuCore          = idCpuCore;
  3430.         pThis->idCpuPackage       = idCpuPackage;
  3431.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
  3432.     }
  3433.     else
  3434.         rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
  3435.  
  3436.     PDMCritSectLeave(&pThis->CritSect);
  3437.     return rc;
  3438. }
  3439.  
  3440. /**
  3441.  * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotPlug}
  3442.  */
  3443. static DECLCALLBACK(int) vmmdevIPort_CpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
  3444. {
  3445.     PVMMDEV pThis = RT_FROM_MEMBER(pInterface, VMMDEV, IPort);
  3446.     int     rc    = VINF_SUCCESS;
  3447.  
  3448.     Log(("vmmdevCpuPlug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
  3449.  
  3450.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3451.  
  3452.     if (pThis->fCpuHotPlugEventsEnabled)
  3453.     {
  3454.         pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Plug;
  3455.         pThis->idCpuCore          = idCpuCore;
  3456.         pThis->idCpuPackage       = idCpuPackage;
  3457.         VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
  3458.     }
  3459.     else
  3460.         rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
  3461.  
  3462.     PDMCritSectLeave(&pThis->CritSect);
  3463.     return rc;
  3464. }
  3465.  
  3466.  
  3467. /* -=-=-=-=-=- Saved State -=-=-=-=-=- */
  3468.  
  3469. /**
  3470.  * @callback_method_impl{FNSSMDEVLIVEEXEC}
  3471.  */
  3472. static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
  3473. {
  3474.     RT_NOREF1(uPass);
  3475.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
  3476.  
  3477.     SSMR3PutBool(pSSM, pThis->fGetHostTimeDisabled);
  3478.     SSMR3PutBool(pSSM, pThis->fBackdoorLogDisabled);
  3479.     SSMR3PutBool(pSSM, pThis->fKeepCredentials);
  3480.     SSMR3PutBool(pSSM, pThis->fHeapEnabled);
  3481.  
  3482.     return VINF_SSM_DONT_CALL_AGAIN;
  3483. }
  3484.  
  3485.  
  3486. /**
  3487.  * @callback_method_impl{FNSSMDEVSAVEEXEC}
  3488.  */
  3489. static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
  3490. {
  3491.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
  3492.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3493.  
  3494.     vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
  3495.  
  3496.     SSMR3PutU32(pSSM, pThis->hypervisorSize);
  3497.     SSMR3PutU32(pSSM, pThis->mouseCapabilities);
  3498.     SSMR3PutS32(pSSM, pThis->mouseXAbs);
  3499.     SSMR3PutS32(pSSM, pThis->mouseYAbs);
  3500.  
  3501.     SSMR3PutBool(pSSM, pThis->fNewGuestFilterMask);
  3502.     SSMR3PutU32(pSSM, pThis->u32NewGuestFilterMask);
  3503.     SSMR3PutU32(pSSM, pThis->u32GuestFilterMask);
  3504.     SSMR3PutU32(pSSM, pThis->u32HostEventFlags);
  3505.     /* The following is not strictly necessary as PGM restores MMIO2, keeping it for historical reasons. */
  3506.     SSMR3PutMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof(pThis->pVMMDevRAMR3->V));
  3507.  
  3508.     SSMR3PutMem(pSSM, &pThis->guestInfo, sizeof(pThis->guestInfo));
  3509.     SSMR3PutU32(pSSM, pThis->fu32AdditionsOk);
  3510.     SSMR3PutU32(pSSM, pThis->u32VideoAccelEnabled);
  3511.     SSMR3PutBool(pSSM, pThis->displayChangeData.fGuestSentChangeEventAck);
  3512.  
  3513.     SSMR3PutU32(pSSM, pThis->guestCaps);
  3514.  
  3515. #ifdef VBOX_WITH_HGCM
  3516.     vmmdevHGCMSaveState(pThis, pSSM);
  3517. #endif /* VBOX_WITH_HGCM */
  3518.  
  3519.     SSMR3PutU32(pSSM, pThis->fHostCursorRequested);
  3520.  
  3521.     SSMR3PutU32(pSSM, pThis->guestInfo2.uFullVersion);
  3522.     SSMR3PutU32(pSSM, pThis->guestInfo2.uRevision);
  3523.     SSMR3PutU32(pSSM, pThis->guestInfo2.fFeatures);
  3524.     SSMR3PutStrZ(pSSM, pThis->guestInfo2.szName);
  3525.     SSMR3PutU32(pSSM, pThis->cFacilityStatuses);
  3526.     for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++)
  3527.     {
  3528.         SSMR3PutU32(pSSM, pThis->aFacilityStatuses[i].enmFacility);
  3529.         SSMR3PutU32(pSSM, pThis->aFacilityStatuses[i].fFlags);
  3530.         SSMR3PutU16(pSSM, (uint16_t)pThis->aFacilityStatuses[i].enmStatus);
  3531.         SSMR3PutS64(pSSM, RTTimeSpecGetNano(&pThis->aFacilityStatuses[i].TimeSpecTS));
  3532.     }
  3533.  
  3534.     /* Heartbeat: */
  3535.     SSMR3PutBool(pSSM, pThis->fHeartbeatActive);
  3536.     SSMR3PutBool(pSSM, pThis->fFlatlined);
  3537.     SSMR3PutU64(pSSM, pThis->nsLastHeartbeatTS);
  3538.     TMR3TimerSave(pThis->pFlatlinedTimer, pSSM);
  3539.  
  3540.     PDMCritSectLeave(&pThis->CritSect);
  3541.     return VINF_SUCCESS;
  3542. }
  3543.  
  3544. /**
  3545.  * @callback_method_impl{FNSSMDEVLOADEXEC}
  3546.  */
  3547. static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
  3548. {
  3549.     /** @todo The code load code is assuming we're always loaded into a freshly
  3550.      *        constructed VM. */
  3551.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
  3552.     int     rc;
  3553.  
  3554.     if (   uVersion > VMMDEV_SAVED_STATE_VERSION
  3555.         || uVersion < 6)
  3556.         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
  3557.  
  3558.     /* config */
  3559.     if (uVersion > VMMDEV_SAVED_STATE_VERSION_VBOX_30)
  3560.     {
  3561.         bool f;
  3562.         rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
  3563.         if (pThis->fGetHostTimeDisabled != f)
  3564.             LogRel(("VMMDev: Config mismatch - fGetHostTimeDisabled: config=%RTbool saved=%RTbool\n", pThis->fGetHostTimeDisabled, f));
  3565.  
  3566.         rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
  3567.         if (pThis->fBackdoorLogDisabled != f)
  3568.             LogRel(("VMMDev: Config mismatch - fBackdoorLogDisabled: config=%RTbool saved=%RTbool\n", pThis->fBackdoorLogDisabled, f));
  3569.  
  3570.         rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
  3571.         if (pThis->fKeepCredentials != f)
  3572.             return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fKeepCredentials: config=%RTbool saved=%RTbool"),
  3573.                                      pThis->fKeepCredentials, f);
  3574.         rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
  3575.         if (pThis->fHeapEnabled != f)
  3576.             return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fHeapEnabled: config=%RTbool saved=%RTbool"),
  3577.                                     pThis->fHeapEnabled, f);
  3578.     }
  3579.  
  3580.     if (uPass != SSM_PASS_FINAL)
  3581.         return VINF_SUCCESS;
  3582.  
  3583.     /* state */
  3584.     SSMR3GetU32(pSSM, &pThis->hypervisorSize);
  3585.     SSMR3GetU32(pSSM, &pThis->mouseCapabilities);
  3586.     SSMR3GetS32(pSSM, &pThis->mouseXAbs);
  3587.     SSMR3GetS32(pSSM, &pThis->mouseYAbs);
  3588.  
  3589.     SSMR3GetBool(pSSM, &pThis->fNewGuestFilterMask);
  3590.     SSMR3GetU32(pSSM, &pThis->u32NewGuestFilterMask);
  3591.     SSMR3GetU32(pSSM, &pThis->u32GuestFilterMask);
  3592.     SSMR3GetU32(pSSM, &pThis->u32HostEventFlags);
  3593.  
  3594.     //SSMR3GetBool(pSSM, &pThis->pVMMDevRAMR3->fHaveEvents);
  3595.     // here be dragons (probably)
  3596.     SSMR3GetMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof (pThis->pVMMDevRAMR3->V));
  3597.  
  3598.     SSMR3GetMem(pSSM, &pThis->guestInfo, sizeof (pThis->guestInfo));
  3599.     SSMR3GetU32(pSSM, &pThis->fu32AdditionsOk);
  3600.     SSMR3GetU32(pSSM, &pThis->u32VideoAccelEnabled);
  3601.     if (uVersion > 10)
  3602.         SSMR3GetBool(pSSM, &pThis->displayChangeData.fGuestSentChangeEventAck);
  3603.  
  3604.     rc = SSMR3GetU32(pSSM, &pThis->guestCaps);
  3605.  
  3606.     /* Attributes which were temporarily introduced in r30072 */
  3607.     if (uVersion == 7)
  3608.     {
  3609.         uint32_t temp;
  3610.         SSMR3GetU32(pSSM, &temp);
  3611.         rc = SSMR3GetU32(pSSM, &temp);
  3612.     }
  3613.     AssertRCReturn(rc, rc);
  3614.  
  3615. #ifdef VBOX_WITH_HGCM
  3616.     rc = vmmdevHGCMLoadState(pThis, pSSM, uVersion);
  3617.     AssertRCReturn(rc, rc);
  3618. #endif /* VBOX_WITH_HGCM */
  3619.  
  3620.     if (uVersion >= 10)
  3621.         rc = SSMR3GetU32(pSSM, &pThis->fHostCursorRequested);
  3622.     AssertRCReturn(rc, rc);
  3623.  
  3624.     if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2)
  3625.     {
  3626.         SSMR3GetU32(pSSM, &pThis->guestInfo2.uFullVersion);
  3627.         SSMR3GetU32(pSSM, &pThis->guestInfo2.uRevision);
  3628.         SSMR3GetU32(pSSM, &pThis->guestInfo2.fFeatures);
  3629.         rc = SSMR3GetStrZ(pSSM, &pThis->guestInfo2.szName[0], sizeof(pThis->guestInfo2.szName));
  3630.         AssertRCReturn(rc, rc);
  3631.     }
  3632.  
  3633.     if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES)
  3634.     {
  3635.         uint32_t cFacilityStatuses;
  3636.         rc = SSMR3GetU32(pSSM, &cFacilityStatuses);
  3637.         AssertRCReturn(rc, rc);
  3638.  
  3639.         for (uint32_t i = 0; i < cFacilityStatuses; i++)
  3640.         {
  3641.             uint32_t uFacility, fFlags;
  3642.             uint16_t uStatus;
  3643.             int64_t  iTimeStampNano;
  3644.  
  3645.             SSMR3GetU32(pSSM, &uFacility);
  3646.             SSMR3GetU32(pSSM, &fFlags);
  3647.             SSMR3GetU16(pSSM, &uStatus);
  3648.             rc = SSMR3GetS64(pSSM, &iTimeStampNano);
  3649.             AssertRCReturn(rc, rc);
  3650.  
  3651.             PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, (VBoxGuestFacilityType)uFacility);
  3652.             AssertLogRelMsgReturn(pEntry,
  3653.                                   ("VMMDev: Ran out of entries restoring the guest facility statuses. Saved state has %u.\n", cFacilityStatuses),
  3654.                                   VERR_OUT_OF_RESOURCES);
  3655.             pEntry->enmStatus = (VBoxGuestFacilityStatus)uStatus;
  3656.             pEntry->fFlags    = fFlags;
  3657.             RTTimeSpecSetNano(&pEntry->TimeSpecTS, iTimeStampNano);
  3658.         }
  3659.     }
  3660.  
  3661.     /*
  3662.      * Heartbeat.
  3663.      */
  3664.     if (uVersion >= VMMDEV_SAVED_STATE_VERSION_HEARTBEAT)
  3665.     {
  3666.         SSMR3GetBool(pSSM, (bool *)&pThis->fHeartbeatActive);
  3667.         SSMR3GetBool(pSSM, (bool *)&pThis->fFlatlined);
  3668.         SSMR3GetU64(pSSM, (uint64_t *)&pThis->nsLastHeartbeatTS);
  3669.         rc = TMR3TimerLoad(pThis->pFlatlinedTimer, pSSM);
  3670.         AssertRCReturn(rc, rc);
  3671.         if (pThis->fFlatlined)
  3672.             LogRel(("vmmdevLoadState: Guest has flatlined. Last heartbeat %'RU64 ns before state was saved.\n",
  3673.                     TMTimerGetNano(pThis->pFlatlinedTimer) - pThis->nsLastHeartbeatTS));
  3674.     }
  3675.  
  3676.     /*
  3677.      * On a resume, we send the capabilities changed message so
  3678.      * that listeners can sync their state again
  3679.      */
  3680.     Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
  3681.     if (pThis->pDrv)
  3682.     {
  3683.         pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
  3684.         if (uVersion >= 10)
  3685.             pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
  3686.                                                /*fVisible=*/!!pThis->fHostCursorRequested,
  3687.                                                /*fAlpha=*/false,
  3688.                                                /*xHot=*/0, /*yHot=*/0,
  3689.                                                /*cx=*/0, /*cy=*/0,
  3690.                                                /*pvShape=*/NULL);
  3691.     }
  3692.  
  3693.     if (pThis->fu32AdditionsOk)
  3694.     {
  3695.         vmmdevLogGuestOsInfo(&pThis->guestInfo);
  3696.         if (pThis->pDrv)
  3697.         {
  3698.             if (pThis->guestInfo2.uFullVersion && pThis->pDrv->pfnUpdateGuestInfo2)
  3699.                 pThis->pDrv->pfnUpdateGuestInfo2(pThis->pDrv, pThis->guestInfo2.uFullVersion, pThis->guestInfo2.szName,
  3700.                                                  pThis->guestInfo2.uRevision, pThis->guestInfo2.fFeatures);
  3701.             if (pThis->pDrv->pfnUpdateGuestInfo)
  3702.                 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
  3703.  
  3704.             if (pThis->pDrv->pfnUpdateGuestStatus)
  3705.             {
  3706.                 for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++) /* ascending order! */
  3707.                     if (   pThis->aFacilityStatuses[i].enmStatus != VBoxGuestFacilityStatus_Inactive
  3708.                         || !pThis->aFacilityStatuses[i].fFixed)
  3709.                         pThis->pDrv->pfnUpdateGuestStatus(pThis->pDrv,
  3710.                                                           pThis->aFacilityStatuses[i].enmFacility,
  3711.                                                           (uint16_t)pThis->aFacilityStatuses[i].enmStatus,
  3712.                                                           pThis->aFacilityStatuses[i].fFlags,
  3713.                                                           &pThis->aFacilityStatuses[i].TimeSpecTS);
  3714.             }
  3715.         }
  3716.     }
  3717.     if (pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
  3718.         pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
  3719.  
  3720.     return VINF_SUCCESS;
  3721. }
  3722.  
  3723. /**
  3724.  * Load state done callback. Notify guest of restore event.
  3725.  *
  3726.  * @returns VBox status code.
  3727.  * @param   pDevIns    The device instance.
  3728.  * @param   pSSM The handle to the saved state.
  3729.  */
  3730. static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
  3731. {
  3732.     RT_NOREF1(pSSM);
  3733.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
  3734.  
  3735. #ifdef VBOX_WITH_HGCM
  3736.     int rc = vmmdevHGCMLoadStateDone(pThis);
  3737.     AssertLogRelRCReturn(rc, rc);
  3738. #endif /* VBOX_WITH_HGCM */
  3739.  
  3740.     /* Reestablish the acceleration status. */
  3741.     if (    pThis->u32VideoAccelEnabled
  3742.         &&  pThis->pDrv)
  3743.     {
  3744.         pThis->pDrv->pfnVideoAccelEnable(pThis->pDrv, !!pThis->u32VideoAccelEnabled, &pThis->pVMMDevRAMR3->vbvaMemory);
  3745.     }
  3746.  
  3747.     VMMDevNotifyGuest(pThis, VMMDEV_EVENT_RESTORED);
  3748.  
  3749.     return VINF_SUCCESS;
  3750. }
  3751.  
  3752.  
  3753. /* -=-=-=-=- PDMDEVREG -=-=-=-=- */
  3754.  
  3755. /**
  3756.  * (Re-)initializes the MMIO2 data.
  3757.  *
  3758.  * @param   pThis           Pointer to the VMMDev instance data.
  3759.  */
  3760. static void vmmdevInitRam(PVMMDEV pThis)
  3761. {
  3762.     memset(pThis->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
  3763.     pThis->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
  3764.     pThis->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
  3765. }
  3766.  
  3767.  
  3768. /**
  3769.  * @interface_method_impl{PDMDEVREG,pfnReset}
  3770.  */
  3771. static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
  3772. {
  3773.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
  3774.     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
  3775.  
  3776.     /*
  3777.      * Reset the mouse integration feature bits
  3778.      */
  3779.     if (pThis->mouseCapabilities & VMMDEV_MOUSE_GUEST_MASK)
  3780.     {
  3781.         pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
  3782.         /* notify the connector */
  3783.         Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
  3784.         pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
  3785.     }
  3786.     pThis->fHostCursorRequested = false;
  3787.  
  3788.     pThis->hypervisorSize = 0;
  3789.  
  3790.     /* re-initialize the VMMDev memory */
  3791.     if (pThis->pVMMDevRAMR3)
  3792.         vmmdevInitRam(pThis);
  3793.  
  3794.     /* credentials have to go away (by default) */
  3795.     if (!pThis->fKeepCredentials)
  3796.     {
  3797.         memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  3798.         memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  3799.         memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  3800.     }
  3801.     memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  3802.     memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  3803.     memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
  3804.  
  3805.     /* Reset means that additions will report again. */
  3806.     const bool fVersionChanged = pThis->fu32AdditionsOk
  3807.                               || pThis->guestInfo.interfaceVersion
  3808.                               || pThis->guestInfo.osType != VBOXOSTYPE_Unknown;
  3809.     if (fVersionChanged)
  3810.         Log(("vmmdevReset: fu32AdditionsOk=%d additionsVersion=%x osType=%#x\n",
  3811.              pThis->fu32AdditionsOk, pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
  3812.     pThis->fu32AdditionsOk = false;
  3813.     memset (&pThis->guestInfo, 0, sizeof (pThis->guestInfo));
  3814.     RT_ZERO(pThis->guestInfo2);
  3815.     const bool fCapsChanged = pThis->guestCaps != 0; /* Report transition to 0. */
  3816.     pThis->guestCaps = 0;
  3817.  
  3818.     /* Clear facilities. No need to tell Main as it will get a
  3819.        pfnUpdateGuestInfo callback. */
  3820.     RTTIMESPEC TimeStampNow;
  3821.     RTTimeNow(&TimeStampNow);
  3822.     uint32_t iFacility = pThis->cFacilityStatuses;
  3823.     while (iFacility-- > 0)
  3824.     {
  3825.         pThis->aFacilityStatuses[iFacility].enmStatus  = VBoxGuestFacilityStatus_Inactive;
  3826.         pThis->aFacilityStatuses[iFacility].TimeSpecTS = TimeStampNow;
  3827.     }
  3828.  
  3829.     /* clear pending display change request. */
  3830.     for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
  3831.     {
  3832.         DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
  3833.         memset (&pRequest->lastReadDisplayChangeRequest, 0, sizeof (pRequest->lastReadDisplayChangeRequest));
  3834.     }
  3835.     pThis->displayChangeData.iCurrentMonitor = 0;
  3836.     pThis->displayChangeData.fGuestSentChangeEventAck = false;
  3837.  
  3838.     /* disable seamless mode */
  3839.     pThis->fLastSeamlessEnabled = false;
  3840.  
  3841.     /* disabled memory ballooning */
  3842.     pThis->cMbMemoryBalloonLast = 0;
  3843.  
  3844.     /* disabled statistics updating */
  3845.     pThis->u32LastStatIntervalSize = 0;
  3846.  
  3847. #ifdef VBOX_WITH_HGCM
  3848.     /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled.  */
  3849.     pThis->u32HGCMEnabled = 0;
  3850. #endif
  3851.  
  3852.     /*
  3853.      * Deactive heartbeat.
  3854.      */
  3855.     if (pThis->fHeartbeatActive)
  3856.     {
  3857.         TMTimerStop(pThis->pFlatlinedTimer);
  3858.         pThis->fFlatlined       = false;
  3859.         pThis->fHeartbeatActive = true;
  3860.     }
  3861.  
  3862.     /*
  3863.      * Clear the event variables.
  3864.      *
  3865.      * XXX By design we should NOT clear pThis->u32HostEventFlags because it is designed
  3866.      *     that way so host events do not depend on guest resets. However, the pending
  3867.      *     event flags actually _were_ cleared since ages so we mask out events from
  3868.      *     clearing which we really need to survive the reset. See xtracker 5767.
  3869.      */
  3870.     pThis->u32HostEventFlags    &= VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
  3871.     pThis->u32GuestFilterMask    = 0;
  3872.     pThis->u32NewGuestFilterMask = 0;
  3873.     pThis->fNewGuestFilterMask   = 0;
  3874.  
  3875.     /*
  3876.      * Call the update functions as required.
  3877.      */
  3878.     if (fVersionChanged && pThis->pDrv && pThis->pDrv->pfnUpdateGuestInfo)
  3879.         pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
  3880.     if (fCapsChanged && pThis->pDrv && pThis->pDrv->pfnUpdateGuestCapabilities)
  3881.         pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
  3882.  
  3883.     /*
  3884.      * Generate a unique session id for this VM; it will be changed for each start, reset or restore.
  3885.      * This can be used for restore detection inside the guest.
  3886.      */
  3887.     pThis->idSession = ASMReadTSC();
  3888.  
  3889.     PDMCritSectLeave(&pThis->CritSect);
  3890. }
  3891.  
  3892.  
  3893. /**
  3894.  * @interface_method_impl{PDMDEVREG,pfnRelocate}
  3895.  */
  3896. static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
  3897. {
  3898.     NOREF(pDevIns);
  3899.     NOREF(offDelta);
  3900. }
  3901.  
  3902.  
  3903. /**
  3904.  * @interface_method_impl{PDMDEVREG,pfnDestruct}
  3905.  */
  3906. static DECLCALLBACK(int) vmmdevDestruct(PPDMDEVINS pDevIns)
  3907. {
  3908.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
  3909.     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
  3910.  
  3911.     /*
  3912.      * Wipe and free the credentials.
  3913.      */
  3914.     if (pThis->pCredentials)
  3915.     {
  3916.         RTMemWipeThoroughly(pThis->pCredentials, sizeof(*pThis->pCredentials), 10);
  3917.         RTMemFree(pThis->pCredentials);
  3918.         pThis->pCredentials = NULL;
  3919.     }
  3920.  
  3921. #ifdef VBOX_WITH_HGCM
  3922.     vmmdevHGCMDestroy(pThis);
  3923.     RTCritSectDelete(&pThis->critsectHGCMCmdList);
  3924. #endif
  3925.  
  3926. #ifndef VBOX_WITHOUT_TESTING_FEATURES
  3927.     /*
  3928.      * Clean up the testing device.
  3929.      */
  3930.     vmmdevTestingTerminate(pDevIns);
  3931. #endif
  3932.  
  3933.     return VINF_SUCCESS;
  3934. }
  3935.  
  3936.  
  3937. /**
  3938.  * @interface_method_impl{PDMDEVREG,pfnConstruct}
  3939.  */
  3940. static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
  3941. {
  3942.     PVMMDEV pThis = PDMINS_2_DATA(pDevIns, PVMMDEV);
  3943.     int rc;
  3944.  
  3945.     Assert(iInstance == 0);
  3946.     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
  3947.  
  3948.     /*
  3949.      * Initialize data (most of it anyway).
  3950.      */
  3951.     /* Save PDM device instance data for future reference. */
  3952.     pThis->pDevIns = pDevIns;
  3953.  
  3954.     /* PCI vendor, just a free bogus value */
  3955.     PCIDevSetVendorId(&pThis->PciDev, 0x80ee);
  3956.     /* device ID */
  3957.     PCIDevSetDeviceId(&pThis->PciDev, 0xcafe);
  3958.     /* class sub code (other type of system peripheral) */
  3959.     PCIDevSetClassSub(&pThis->PciDev, 0x80);
  3960.     /* class base code (base system peripheral) */
  3961.     PCIDevSetClassBase(&pThis->PciDev, 0x08);
  3962.     /* header type */
  3963.     PCIDevSetHeaderType(&pThis->PciDev, 0x00);
  3964.     /* interrupt on pin 0 */
  3965.     PCIDevSetInterruptPin(&pThis->PciDev, 0x01);
  3966.  
  3967.     RTTIMESPEC TimeStampNow;
  3968.     RTTimeNow(&TimeStampNow);
  3969.     vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxGuestDriver, true /*fFixed*/, &TimeStampNow);
  3970.     vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxService,     true /*fFixed*/, &TimeStampNow);
  3971.     vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxTrayClient,  true /*fFixed*/, &TimeStampNow);
  3972.     vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Seamless,        true /*fFixed*/, &TimeStampNow);
  3973.     vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Graphics,        true /*fFixed*/, &TimeStampNow);
  3974.     Assert(pThis->cFacilityStatuses == 5);
  3975.  
  3976.     /*
  3977.      * Interfaces
  3978.      */
  3979.     /* IBase */
  3980.     pThis->IBase.pfnQueryInterface          = vmmdevPortQueryInterface;
  3981.  
  3982.     /* VMMDev port */
  3983.     pThis->IPort.pfnQueryAbsoluteMouse      = vmmdevIPort_QueryAbsoluteMouse;
  3984.     pThis->IPort.pfnSetAbsoluteMouse        = vmmdevIPort_SetAbsoluteMouse ;
  3985.     pThis->IPort.pfnQueryMouseCapabilities  = vmmdevIPort_QueryMouseCapabilities;
  3986.     pThis->IPort.pfnUpdateMouseCapabilities = vmmdevIPort_UpdateMouseCapabilities;
  3987.     pThis->IPort.pfnRequestDisplayChange    = vmmdevIPort_RequestDisplayChange;
  3988.     pThis->IPort.pfnSetCredentials          = vmmdevIPort_SetCredentials;
  3989.     pThis->IPort.pfnVBVAChange              = vmmdevIPort_VBVAChange;
  3990.     pThis->IPort.pfnRequestSeamlessChange   = vmmdevIPort_RequestSeamlessChange;
  3991.     pThis->IPort.pfnSetMemoryBalloon        = vmmdevIPort_SetMemoryBalloon;
  3992.     pThis->IPort.pfnSetStatisticsInterval   = vmmdevIPort_SetStatisticsInterval;
  3993.     pThis->IPort.pfnVRDPChange              = vmmdevIPort_VRDPChange;
  3994.     pThis->IPort.pfnCpuHotUnplug            = vmmdevIPort_CpuHotUnplug;
  3995.     pThis->IPort.pfnCpuHotPlug              = vmmdevIPort_CpuHotPlug;
  3996.  
  3997.     /* Shared folder LED */
  3998.     pThis->SharedFolders.Led.u32Magic       = PDMLED_MAGIC;
  3999.     pThis->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
  4000.  
  4001. #ifdef VBOX_WITH_HGCM
  4002.     /* HGCM port */
  4003.     pThis->IHGCMPort.pfnCompleted           = hgcmCompleted;
  4004. #endif
  4005.  
  4006.     pThis->pCredentials = (VMMDEVCREDS *)RTMemAllocZ(sizeof(*pThis->pCredentials));
  4007.     if (!pThis->pCredentials)
  4008.         return VERR_NO_MEMORY;
  4009.  
  4010.  
  4011.     /*
  4012.      * Validate and read the configuration.
  4013.      */
  4014.     PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
  4015.                                   "GetHostTimeDisabled|"
  4016.                                   "BackdoorLogDisabled|"
  4017.                                   "KeepCredentials|"
  4018.                                   "HeapEnabled|"
  4019.                                   "RZEnabled|"
  4020.                                   "GuestCoreDumpEnabled|"
  4021.                                   "GuestCoreDumpDir|"
  4022.                                   "GuestCoreDumpCount|"
  4023.                                   "HeartbeatInterval|"
  4024.                                   "HeartbeatTimeout|"
  4025.                                   "TestingEnabled|"
  4026.                                   "TestingMMIO|"
  4027.                                   "TestintXmlOutputFile"
  4028.                                   ,
  4029.                                   "");
  4030.  
  4031.     rc = CFGMR3QueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
  4032.     if (RT_FAILURE(rc))
  4033.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4034.                                 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
  4035.  
  4036.     rc = CFGMR3QueryBoolDef(pCfg, "BackdoorLogDisabled", &pThis->fBackdoorLogDisabled, false);
  4037.     if (RT_FAILURE(rc))
  4038.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4039.                                 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
  4040.  
  4041.     rc = CFGMR3QueryBoolDef(pCfg, "KeepCredentials", &pThis->fKeepCredentials, false);
  4042.     if (RT_FAILURE(rc))
  4043.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4044.                                 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
  4045.  
  4046.     rc = CFGMR3QueryBoolDef(pCfg, "HeapEnabled", &pThis->fHeapEnabled, true);
  4047.     if (RT_FAILURE(rc))
  4048.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4049.                                 N_("Configuration error: Failed querying \"HeapEnabled\" as a boolean"));
  4050.  
  4051.     rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &pThis->fRZEnabled, true);
  4052.     if (RT_FAILURE(rc))
  4053.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4054.                                 N_("Configuration error: Failed querying \"RZEnabled\" as a boolean"));
  4055.  
  4056.     rc = CFGMR3QueryBoolDef(pCfg, "GuestCoreDumpEnabled", &pThis->fGuestCoreDumpEnabled, false);
  4057.     if (RT_FAILURE(rc))
  4058.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4059.                                 N_("Configuration error: Failed querying \"GuestCoreDumpEnabled\" as a boolean"));
  4060.  
  4061.     char *pszGuestCoreDumpDir = NULL;
  4062.     rc = CFGMR3QueryStringAllocDef(pCfg, "GuestCoreDumpDir", &pszGuestCoreDumpDir, "");
  4063.     if (RT_FAILURE(rc))
  4064.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4065.                                 N_("Configuration error: Failed querying \"GuestCoreDumpDir\" as a string"));
  4066.  
  4067.     RTStrCopy(pThis->szGuestCoreDumpDir, sizeof(pThis->szGuestCoreDumpDir), pszGuestCoreDumpDir);
  4068.     MMR3HeapFree(pszGuestCoreDumpDir);
  4069.  
  4070.     rc = CFGMR3QueryU32Def(pCfg, "GuestCoreDumpCount", &pThis->cGuestCoreDumps, 3);
  4071.     if (RT_FAILURE(rc))
  4072.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4073.                                 N_("Configuration error: Failed querying \"GuestCoreDumpCount\" as a 32-bit unsigned integer"));
  4074.  
  4075.     rc = CFGMR3QueryU64Def(pCfg, "HeartbeatInterval", &pThis->cNsHeartbeatInterval, VMMDEV_HEARTBEAT_DEFAULT_INTERVAL);
  4076.     if (RT_FAILURE(rc))
  4077.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4078.                                 N_("Configuration error: Failed querying \"HeartbeatInterval\" as a 64-bit unsigned integer"));
  4079.     if (pThis->cNsHeartbeatInterval < RT_NS_100MS / 2)
  4080.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4081.                                 N_("Configuration error: Heartbeat interval \"HeartbeatInterval\" too small"));
  4082.  
  4083.     rc = CFGMR3QueryU64Def(pCfg, "HeartbeatTimeout", &pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval * 2);
  4084.     if (RT_FAILURE(rc))
  4085.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4086.                                 N_("Configuration error: Failed querying \"HeartbeatTimeout\" as a 64-bit unsigned integer"));
  4087.     if (pThis->cNsHeartbeatTimeout < RT_NS_100MS)
  4088.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4089.                                 N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" too small"));
  4090.     if (pThis->cNsHeartbeatTimeout <= pThis->cNsHeartbeatInterval + RT_NS_10MS)
  4091.         return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
  4092.                                    N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" value (%'ull ns) is too close to the interval (%'ull ns)"),
  4093.                                    pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval);
  4094.  
  4095. #ifndef VBOX_WITHOUT_TESTING_FEATURES
  4096.     rc = CFGMR3QueryBoolDef(pCfg, "TestingEnabled", &pThis->fTestingEnabled, false);
  4097.     if (RT_FAILURE(rc))
  4098.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4099.                                 N_("Configuration error: Failed querying \"TestingEnabled\" as a boolean"));
  4100.     rc = CFGMR3QueryBoolDef(pCfg, "TestingMMIO", &pThis->fTestingMMIO, false);
  4101.     if (RT_FAILURE(rc))
  4102.         return PDMDEV_SET_ERROR(pDevIns, rc,
  4103.                                 N_("Configuration error: Failed querying \"TestingMMIO\" as a boolean"));
  4104.     rc = CFGMR3QueryStringAllocDef(pCfg, "TestintXmlOutputFile", &pThis->pszTestingXmlOutput, NULL);
  4105.     if (RT_FAILURE(rc))
  4106.         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestintXmlOutputFile\" as a string"));
  4107.  
  4108.     /** @todo image-to-load-filename? */
  4109. #endif
  4110.  
  4111.     pThis->cbGuestRAM = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
  4112.  
  4113.     /*
  4114.      * We do our own locking entirely. So, install NOP critsect for the device
  4115.      * and create our own critsect for use where it really matters (++).
  4116.      */
  4117.     rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
  4118.     AssertRCReturn(rc, rc);
  4119.     rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev#%u", iInstance);
  4120.     AssertRCReturn(rc, rc);
  4121.  
  4122.     /*
  4123.      * Register the backdoor logging port
  4124.      */
  4125.     rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog,
  4126.                                  NULL, NULL, NULL, "VMMDev backdoor logging");
  4127.     AssertRCReturn(rc, rc);
  4128.  
  4129. #ifdef VMMDEV_WITH_ALT_TIMESYNC
  4130.     /*
  4131.      * Alternative timesync source.
  4132.      *
  4133.      * This was orignally added for creating a simple time sync service in an
  4134.      * OpenBSD guest without requiring VBoxGuest and VBoxService to be ported
  4135.      * first.  We keep it in case it comes in handy.
  4136.      */
  4137.     rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL,
  4138.                                  vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead,
  4139.                                  NULL, NULL, "VMMDev timesync backdoor");
  4140.     AssertRCReturn(rc, rc);
  4141. #endif
  4142.  
  4143.     /*
  4144.      * Register the PCI device.
  4145.      */
  4146.     rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
  4147.     if (RT_FAILURE(rc))
  4148.         return rc;
  4149.     if (pThis->PciDev.uDevFn != 32 || iInstance != 0)
  4150.         Log(("!!WARNING!!: pThis->PciDev.uDevFn=%d (ignore if testcase or no started by Main)\n", pThis->PciDev.uDevFn));
  4151.     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
  4152.     if (RT_FAILURE(rc))
  4153.         return rc;
  4154.     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
  4155.     if (RT_FAILURE(rc))
  4156.         return rc;
  4157.     if (pThis->fHeapEnabled)
  4158.     {
  4159.         rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, VMMDEV_HEAP_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH, vmmdevIORAMRegionMap);
  4160.         if (RT_FAILURE(rc))
  4161.             return rc;
  4162.     }
  4163.  
  4164.     /*
  4165.      * Allocate and initialize the MMIO2 memory.
  4166.      */
  4167.     rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->PciDev, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0 /*fFlags*/,
  4168.                                 (void **)&pThis->pVMMDevRAMR3, "VMMDev");
  4169.     if (RT_FAILURE(rc))
  4170.         return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
  4171.                                    N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
  4172.     vmmdevInitRam(pThis);
  4173.  
  4174.     if (pThis->fHeapEnabled)
  4175.     {
  4176.         rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->PciDev, 2 /*iRegion*/, VMMDEV_HEAP_SIZE, 0 /*fFlags*/,
  4177.                                     (void **)&pThis->pVMMDevHeapR3, "VMMDev Heap");
  4178.         if (RT_FAILURE(rc))
  4179.             return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
  4180.                                        N_("Failed to allocate %u bytes of memory for the VMM device heap"), PAGE_SIZE);
  4181.  
  4182.         /* Register the memory area with PDM so HM can access it before it's mapped. */
  4183.         rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
  4184.         AssertLogRelRCReturn(rc, rc);
  4185.     }
  4186.  
  4187. #ifndef VBOX_WITHOUT_TESTING_FEATURES
  4188.     /*
  4189.      * Initialize testing.
  4190.      */
  4191.     rc = vmmdevTestingInitialize(pDevIns);
  4192.     if (RT_FAILURE(rc))
  4193.         return rc;
  4194. #endif
  4195.  
  4196.     /*
  4197.      * Get the corresponding connector interface
  4198.      */
  4199.     rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "VMM Driver Port");
  4200.     if (RT_SUCCESS(rc))
  4201.     {
  4202.         pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIVMMDEVCONNECTOR);
  4203.         AssertMsgReturn(pThis->pDrv, ("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
  4204. #ifdef VBOX_WITH_HGCM
  4205.         pThis->pHGCMDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHGCMCONNECTOR);
  4206.         if (!pThis->pHGCMDrv)
  4207.         {
  4208.             Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Rrc\n", rc));
  4209.             /* this is not actually an error, just means that there is no support for HGCM */
  4210.         }
  4211. #endif
  4212.         /* Query the initial balloon size. */
  4213.         AssertPtr(pThis->pDrv->pfnQueryBalloonSize);
  4214.         rc = pThis->pDrv->pfnQueryBalloonSize(pThis->pDrv, &pThis->cMbMemoryBalloon);
  4215.         AssertRC(rc);
  4216.  
  4217.         Log(("Initial balloon size %x\n", pThis->cMbMemoryBalloon));
  4218.     }
  4219.     else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
  4220.     {
  4221.         Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
  4222.         rc = VINF_SUCCESS;
  4223.     }
  4224.     else
  4225.         AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Rrc\n", rc), rc);
  4226.  
  4227.     /*
  4228.      * Attach status driver for shared folders (optional).
  4229.      */
  4230.     PPDMIBASE pBase;
  4231.     rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
  4232.     if (RT_SUCCESS(rc))
  4233.         pThis->SharedFolders.pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
  4234.     else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
  4235.     {
  4236.         AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
  4237.         return rc;
  4238.     }
  4239.  
  4240.     /*
  4241.      * Register saved state and init the HGCM CmdList critsect.
  4242.      */
  4243.     rc = PDMDevHlpSSMRegisterEx(pDevIns, VMMDEV_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
  4244.                                 NULL, vmmdevLiveExec, NULL,
  4245.                                 NULL, vmmdevSaveExec, NULL,
  4246.                                 NULL, vmmdevLoadExec, vmmdevLoadStateDone);
  4247.     AssertRCReturn(rc, rc);
  4248.  
  4249.     /*
  4250.      * Create heartbeat checking timer.
  4251.      */
  4252.     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vmmDevHeartbeatFlatlinedTimer, pThis,
  4253.                                 TMTIMER_FLAGS_NO_CRIT_SECT, "Heartbeat flatlined", &pThis->pFlatlinedTimer);
  4254.     AssertRCReturn(rc, rc);
  4255.  
  4256. #ifdef VBOX_WITH_HGCM
  4257.     pThis->pHGCMCmdList = NULL;
  4258.     rc = RTCritSectInit(&pThis->critsectHGCMCmdList);
  4259.     AssertRCReturn(rc, rc);
  4260.     pThis->u32HGCMEnabled = 0;
  4261. #endif /* VBOX_WITH_HGCM */
  4262.  
  4263.     /*
  4264.      * In this version of VirtualBox the GUI checks whether "needs host cursor"
  4265.      * changes.
  4266.      */
  4267.     pThis->mouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
  4268.  
  4269.     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Memory balloon size", "/Devices/VMMDev/BalloonChunks");
  4270.  
  4271.     /*
  4272.      * Generate a unique session id for this VM; it will be changed for each
  4273.      * start, reset or restore. This can be used for restore detection inside
  4274.      * the guest.
  4275.      */
  4276.     pThis->idSession = ASMReadTSC();
  4277.     return rc;
  4278. }
  4279.  
  4280. /**
  4281.  * The device registration structure.
  4282.  */
  4283. extern "C" const PDMDEVREG g_DeviceVMMDev =
  4284. {
  4285.     /* u32Version */
  4286.     PDM_DEVREG_VERSION,
  4287.     /* szName */
  4288.     "VMMDev",
  4289.     /* szRCMod */
  4290.     "VBoxDDRC.rc",
  4291.     /* szR0Mod */
  4292.     "VBoxDDR0.r0",
  4293.     /* pszDescription */
  4294.     "VirtualBox VMM Device\n",
  4295.     /* fFlags */
  4296.     PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
  4297.     /* fClass */
  4298.     PDM_DEVREG_CLASS_VMM_DEV,
  4299.     /* cMaxInstances */
  4300.     1,
  4301.     /* cbInstance */
  4302.     sizeof(VMMDevState),
  4303.     /* pfnConstruct */
  4304.     vmmdevConstruct,
  4305.     /* pfnDestruct */
  4306.     vmmdevDestruct,
  4307.     /* pfnRelocate */
  4308.     vmmdevRelocate,
  4309.     /* pfnMemSetup */
  4310.     NULL,
  4311.     /* pfnPowerOn */
  4312.     NULL,
  4313.     /* pfnReset */
  4314.     vmmdevReset,
  4315.     /* pfnSuspend */
  4316.     NULL,
  4317.     /* pfnResume */
  4318.     NULL,
  4319.     /* pfnAttach */
  4320.     NULL,
  4321.     /* pfnDetach */
  4322.     NULL,
  4323.     /* pfnQueryInterface. */
  4324.     NULL,
  4325.     /* pfnInitComplete */
  4326.     NULL,
  4327.     /* pfnPowerOff */
  4328.     NULL,
  4329.     /* pfnSoftReset */
  4330.     NULL,
  4331.     /* u32VersionEnd */
  4332.     PDM_DEVREG_VERSION
  4333. };
  4334. #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Advertisement
Add Comment
Please, Sign In to add comment