VirtualBox

source: vbox/trunk/src/VBox/Devices/VMMDev/VMMDev.cpp@ 78260

Last change on this file since 78260 was 77243, checked in by vboxsync, 6 years ago

HGCM,SharedFolders: Added new variation on the HGCM page list type that does not use a bounce buffer. bugref:9172

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette