VirtualBox

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

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

Devices: Use new volatile SSM getters and enum macros. bugref:9218

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