VirtualBox

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

Last change on this file since 95818 was 94478, checked in by vboxsync, 3 years ago

VBox/ostypes.h+Main/Global,Appliance+FE/Qt: Some Solaris OStype cleanup:
the Solaris 10 10/09 OStype was accidentally entwined with OpenSolaris in
the Global::sOSTypes[] table so separate them into a Solaris 10U8
(10/09) OS type and an OpenSolaris/Illumos/OpenIndiana OS type. Also
update the GUI icon and regex matching for these and other Solaris
versions.

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