VirtualBox

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

Last change on this file since 73242 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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