VirtualBox

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

Last change on this file since 81067 was 81031, checked in by vboxsync, 5 years ago

PDM,Devices: Moving the PDMPCIDEV structures into the PDMDEVINS allocation. Preps for extending the config space to 4KB. bugref:9218

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