VirtualBox

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

Last change on this file since 97441 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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