VirtualBox

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

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

VMMDev,PGM: New I/O port for ACKing IRQs and retreiving pending events. This is handled in ring-0/raw-mode and saves a bit of time compared to the ring-3 trip we've been doing for VMMDevReq_AcknowledgeEvents thus far. Requires the start of the VMMDev memory being mapped into R00/RC, the former requires some hacks on linux+windows as RTR0MemObjMapKernelEx is missing some functionality here. bugref:9172

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

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