VirtualBox

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

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

VMMDev: Use RTMemFreeZ. bugref:9698

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

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