VirtualBox

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

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

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