VirtualBox

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

Last change on this file since 57730 was 57602, checked in by vboxsync, 10 years ago

VMMDev: log the guest OS type in plain text for convenience when analyzing VBox.log files

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

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