VirtualBox

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

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

VMMDev/HGCM: Eliminated the unlock-delay hack (from 3.0) and implemented lock based approach for HGCM request (disabled). bugref:9172 [build fix]

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