VirtualBox

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

Last change on this file since 98063 was 97816, checked in by vboxsync, 2 years ago

VMMDev: Mouse Integration: do not double-invert horizontal and vertical scroll wheel values when passing data to the guest, bugref:10285.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 210.8 KB
Line 
1/* $Id: VMMDev.cpp 97816 2022-12-15 19:48:40Z 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_GetMouseStatusEx.
1150 *
1151 * @returns VBox status code that the guest should see.
1152 * @param pThis The VMMDev shared instance data.
1153 * @param pReqHdr The header of the request to handle.
1154 */
1155static int vmmdevReqHandler_GetMouseStatusEx(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1156{
1157 VMMDevReqMouseStatusEx *pReq = (VMMDevReqMouseStatusEx *)pReqHdr;
1158 AssertMsgReturn(pReq->Core.header.size == sizeof(*pReq), ("%u\n", pReq->Core.header.size), VERR_INVALID_PARAMETER);
1159
1160 /* Main will convert host mouse buttons state obtained from GUI
1161 * into PDMIMOUSEPORT_BUTTON_XXX representation. Guest will expect it
1162 * to VMMDEV_MOUSE_BUTTON_XXX representaion. Make sure both
1163 * representations are identical. */
1164 AssertCompile(VMMDEV_MOUSE_BUTTON_LEFT == PDMIMOUSEPORT_BUTTON_LEFT);
1165 AssertCompile(VMMDEV_MOUSE_BUTTON_RIGHT == PDMIMOUSEPORT_BUTTON_RIGHT);
1166 AssertCompile(VMMDEV_MOUSE_BUTTON_MIDDLE == PDMIMOUSEPORT_BUTTON_MIDDLE);
1167 AssertCompile(VMMDEV_MOUSE_BUTTON_X1 == PDMIMOUSEPORT_BUTTON_X1);
1168 AssertCompile(VMMDEV_MOUSE_BUTTON_X2 == PDMIMOUSEPORT_BUTTON_X2);
1169
1170 pReq->Core.mouseFeatures = pThis->fMouseCapabilities & VMMDEV_MOUSE_MASK;
1171 pReq->Core.pointerXPos = pThis->xMouseAbs;
1172 pReq->Core.pointerYPos = pThis->yMouseAbs;
1173 pReq->dz = pThis->dzMouse;
1174 pReq->dw = pThis->dwMouse;
1175 pReq->fButtons = pThis->fMouseButtons;
1176 LogRel2(("VMMDev: vmmdevReqHandler_GetMouseStatusEx: mouseFeatures=%#x, xAbs=%d, yAbs=%d, zAbs=%d, wMouseRel=%d, fButtons=0x%x\n",
1177 pReq->Core.mouseFeatures, pReq->Core.pointerXPos, pReq->Core.pointerYPos, pReq->dz, pReq->dw, pReq->fButtons));
1178 return VINF_SUCCESS;
1179}
1180
1181
1182/**
1183 * Handles VMMDevReq_SetMouseStatus.
1184 *
1185 * @returns VBox status code that the guest should see.
1186 * @param pThis The VMMDev shared instance data.
1187 * @param pThisCC The VMMDev ring-3 instance data.
1188 * @param pReqHdr The header of the request to handle.
1189 */
1190static int vmmdevReqHandler_SetMouseStatus(PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1191{
1192 VMMDevReqMouseStatus *pReq = (VMMDevReqMouseStatus *)pReqHdr;
1193 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1194
1195 LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: mouseFeatures=%#x\n", pReq->mouseFeatures));
1196
1197 bool fNotify = false;
1198 if ( (pReq->mouseFeatures & VMMDEV_MOUSE_NOTIFY_HOST_MASK)
1199 != ( pThis->fMouseCapabilities
1200 & VMMDEV_MOUSE_NOTIFY_HOST_MASK))
1201 fNotify = true;
1202
1203 pThis->fMouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
1204 pThis->fMouseCapabilities |= (pReq->mouseFeatures & VMMDEV_MOUSE_GUEST_MASK);
1205
1206 LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: New host capabilities: %#x\n", pThis->fMouseCapabilities));
1207
1208 /*
1209 * Notify connector if something changed.
1210 */
1211 if (fNotify)
1212 {
1213 LogRelFlow(("VMMDev: vmmdevReqHandler_SetMouseStatus: Notifying connector\n"));
1214 pThisCC->pDrv->pfnUpdateMouseCapabilities(pThisCC->pDrv, pThis->fMouseCapabilities);
1215 }
1216
1217 return VINF_SUCCESS;
1218}
1219
1220static int vmmdevVerifyPointerShape(VMMDevReqMousePointer *pReq)
1221{
1222 /* Should be enough for most mouse pointers. */
1223 if (pReq->width > 8192 || pReq->height > 8192)
1224 return VERR_INVALID_PARAMETER;
1225
1226 uint32_t cbShape = (pReq->width + 7) / 8 * pReq->height; /* size of the AND mask */
1227 cbShape = ((cbShape + 3) & ~3) + pReq->width * 4 * pReq->height; /* + gap + size of the XOR mask */
1228 if (RT_UOFFSETOF(VMMDevReqMousePointer, pointerData) + cbShape > pReq->header.size)
1229 return VERR_INVALID_PARAMETER;
1230
1231 return VINF_SUCCESS;
1232}
1233
1234/**
1235 * Handles VMMDevReq_SetPointerShape.
1236 *
1237 * @returns VBox status code that the guest should see.
1238 * @param pThis The VMMDev shared instance data.
1239 * @param pThisCC The VMMDev ring-3 instance data.
1240 * @param pReqHdr The header of the request to handle.
1241 */
1242static int vmmdevReqHandler_SetPointerShape(PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1243{
1244 VMMDevReqMousePointer *pReq = (VMMDevReqMousePointer *)pReqHdr;
1245 if (pReq->header.size < sizeof(*pReq))
1246 {
1247 AssertMsg(pReq->header.size == 0x10028 && pReq->header.version == 10000, /* don't complain about legacy!!! */
1248 ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
1249 pReq->header.size, pReq->header.size, pReq->header.version));
1250 return VERR_INVALID_PARAMETER;
1251 }
1252
1253 bool fVisible = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_VISIBLE);
1254 bool fAlpha = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_ALPHA);
1255 bool fShape = RT_BOOL(pReq->fFlags & VBOX_MOUSE_POINTER_SHAPE);
1256
1257 Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
1258 fVisible, fAlpha, fShape, pReq->width, pReq->height));
1259
1260 if (pReq->header.size == sizeof(VMMDevReqMousePointer))
1261 {
1262 /* The guest did not provide the shape actually. */
1263 fShape = false;
1264 }
1265
1266 /* forward call to driver */
1267 if (fShape)
1268 {
1269 int rc = vmmdevVerifyPointerShape(pReq);
1270 if (RT_FAILURE(rc))
1271 return rc;
1272
1273 pThisCC->pDrv->pfnUpdatePointerShape(pThisCC->pDrv,
1274 fVisible,
1275 fAlpha,
1276 pReq->xHot, pReq->yHot,
1277 pReq->width, pReq->height,
1278 pReq->pointerData);
1279 }
1280 else
1281 {
1282 pThisCC->pDrv->pfnUpdatePointerShape(pThisCC->pDrv,
1283 fVisible,
1284 0,
1285 0, 0,
1286 0, 0,
1287 NULL);
1288 }
1289
1290 pThis->fHostCursorRequested = fVisible;
1291 return VINF_SUCCESS;
1292}
1293
1294
1295/**
1296 * Handles VMMDevReq_GetHostTime.
1297 *
1298 * @returns VBox status code that the guest should see.
1299 * @param pDevIns The device instance.
1300 * @param pThis The VMMDev shared instance data.
1301 * @param pReqHdr The header of the request to handle.
1302 */
1303static int vmmdevReqHandler_GetHostTime(PPDMDEVINS pDevIns, PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1304{
1305 VMMDevReqHostTime *pReq = (VMMDevReqHostTime *)pReqHdr;
1306 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1307
1308 if (RT_LIKELY(!pThis->fGetHostTimeDisabled))
1309 {
1310 RTTIMESPEC now;
1311 pReq->time = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &now));
1312 return VINF_SUCCESS;
1313 }
1314 return VERR_NOT_SUPPORTED;
1315}
1316
1317
1318/**
1319 * Handles VMMDevReq_GetHypervisorInfo.
1320 *
1321 * @returns VBox status code that the guest should see.
1322 * @param pDevIns The device instance.
1323 * @param pReqHdr The header of the request to handle.
1324 */
1325static int vmmdevReqHandler_GetHypervisorInfo(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
1326{
1327 VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
1328 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1329
1330#if 1 /* Obsolete for now, only used for raw-mode. */
1331 RT_NOREF(pDevIns);
1332 pReq->hypervisorSize = 0;
1333 return VINF_SUCCESS;
1334#else
1335 return PGMR3MappingsSize(PDMDevHlpGetVM(pDevIns), &pReq->hypervisorSize);
1336#endif
1337}
1338
1339
1340/**
1341 * Handles VMMDevReq_SetHypervisorInfo.
1342 *
1343 * @returns VBox status code that the guest should see.
1344 * @param pDevIns The device instance.
1345 * @param pReqHdr The header of the request to handle.
1346 */
1347static int vmmdevReqHandler_SetHypervisorInfo(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
1348{
1349 VMMDevReqHypervisorInfo *pReq = (VMMDevReqHypervisorInfo *)pReqHdr;
1350 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1351
1352 int rc;
1353#if 1 /* Obsolete for now, only used for raw-mode. */
1354 RT_NOREF(pDevIns);
1355 if (pReq->hypervisorStart == 0 || pReq->hypervisorSize == 0)
1356 rc = VINF_SUCCESS;
1357 else
1358 rc = VERR_TRY_AGAIN;
1359#else
1360 PVM pVM = PDMDevHlpGetVM(pDevIns);
1361 if (pReq->hypervisorStart == 0)
1362 rc = PGMR3MappingsUnfix(pVM);
1363 else
1364 {
1365 /* only if the client has queried the size before! */
1366 uint32_t cbMappings;
1367 rc = PGMR3MappingsSize(pVM, &cbMappings);
1368 if (RT_SUCCESS(rc) && pReq->hypervisorSize == cbMappings)
1369 {
1370 /* new reservation */
1371 rc = PGMR3MappingsFix(pVM, pReq->hypervisorStart, pReq->hypervisorSize);
1372 LogRel(("VMMDev: Guest reported fixed hypervisor window at 0%010x LB %#x (rc=%Rrc)\n",
1373 pReq->hypervisorStart, pReq->hypervisorSize, rc));
1374 }
1375 else if (RT_FAILURE(rc)) /** @todo r=bird: This should've been RT_SUCCESS(rc)) */
1376 rc = VERR_TRY_AGAIN;
1377 }
1378#endif
1379 return rc;
1380}
1381
1382
1383/**
1384 * Handles VMMDevReq_RegisterPatchMemory.
1385 *
1386 * @returns VBox status code that the guest should see.
1387 * @param pDevIns The device instance.
1388 * @param pReqHdr The header of the request to handle.
1389 */
1390static int vmmdevReqHandler_RegisterPatchMemory(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
1391{
1392 VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
1393 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1394
1395 return PDMDevHlpVMMRegisterPatchMemory(pDevIns, pReq->pPatchMem, pReq->cbPatchMem);
1396}
1397
1398
1399/**
1400 * Handles VMMDevReq_DeregisterPatchMemory.
1401 *
1402 * @returns VBox status code that the guest should see.
1403 * @param pDevIns The device instance.
1404 * @param pReqHdr The header of the request to handle.
1405 */
1406static int vmmdevReqHandler_DeregisterPatchMemory(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
1407{
1408 VMMDevReqPatchMemory *pReq = (VMMDevReqPatchMemory *)pReqHdr;
1409 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1410
1411 return PDMDevHlpVMMDeregisterPatchMemory(pDevIns, pReq->pPatchMem, pReq->cbPatchMem);
1412}
1413
1414
1415/**
1416 * Handles VMMDevReq_SetPowerStatus.
1417 *
1418 * @returns VBox status code that the guest should see.
1419 * @param pDevIns The device instance.
1420 * @param pThis The VMMDev shared instance data.
1421 * @param pReqHdr The header of the request to handle.
1422 */
1423static int vmmdevReqHandler_SetPowerStatus(PPDMDEVINS pDevIns, PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1424{
1425 VMMDevPowerStateRequest *pReq = (VMMDevPowerStateRequest *)pReqHdr;
1426 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1427
1428 switch (pReq->powerState)
1429 {
1430 case VMMDevPowerState_Pause:
1431 {
1432 LogRel(("VMMDev: Guest requests the VM to be suspended (paused)\n"));
1433 return PDMDevHlpVMSuspend(pDevIns);
1434 }
1435
1436 case VMMDevPowerState_PowerOff:
1437 {
1438 LogRel(("VMMDev: Guest requests the VM to be turned off\n"));
1439 return PDMDevHlpVMPowerOff(pDevIns);
1440 }
1441
1442 case VMMDevPowerState_SaveState:
1443 {
1444 if (pThis->fAllowGuestToSaveState)
1445 {
1446 LogRel(("VMMDev: Guest requests the VM to be saved and powered off\n"));
1447 return PDMDevHlpVMSuspendSaveAndPowerOff(pDevIns);
1448 }
1449 LogRel(("VMMDev: Guest requests the VM to be saved and powered off, declined\n"));
1450 return VERR_ACCESS_DENIED;
1451 }
1452
1453 default:
1454 AssertMsgFailed(("VMMDev: Invalid power state request: %d\n", pReq->powerState));
1455 return VERR_INVALID_PARAMETER;
1456 }
1457}
1458
1459
1460/**
1461 * Handles VMMDevReq_GetDisplayChangeRequest
1462 *
1463 * @returns VBox status code that the guest should see.
1464 * @param pThis The VMMDev shared instance data.
1465 * @param pReqHdr The header of the request to handle.
1466 * @remarks Deprecated.
1467 */
1468static int vmmdevReqHandler_GetDisplayChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1469{
1470 VMMDevDisplayChangeRequest *pReq = (VMMDevDisplayChangeRequest *)pReqHdr;
1471 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1472
1473 DISPLAYCHANGEREQUEST *pDispRequest = &pThis->displayChangeData.aRequests[0];
1474
1475 if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
1476 {
1477 /* Current request has been read at least once. */
1478 pDispRequest->fPending = false;
1479
1480 /* Remember which resolution the client has queried, subsequent reads
1481 * will return the same values. */
1482 pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
1483 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1484 }
1485
1486 /* If not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1487 * read the last valid video mode hint. This happens when the guest X server
1488 * determines the initial mode. */
1489 VMMDevDisplayDef const *pDisplayDef = pThis->displayChangeData.fGuestSentChangeEventAck ?
1490 &pDispRequest->lastReadDisplayChangeRequest :
1491 &pDispRequest->displayChangeRequest;
1492 pReq->xres = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_CX) ? pDisplayDef->cx : 0;
1493 pReq->yres = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_CY) ? pDisplayDef->cy : 0;
1494 pReq->bpp = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_BPP) ? pDisplayDef->cBitsPerPixel : 0;
1495
1496 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n", pReq->xres, pReq->yres, pReq->bpp));
1497
1498 return VINF_SUCCESS;
1499}
1500
1501
1502/**
1503 * Handles VMMDevReq_GetDisplayChangeRequest2.
1504 *
1505 * @returns VBox status code that the guest should see.
1506 * @param pDevIns The device instance.
1507 * @param pThis The VMMDev shared instance data.
1508 * @param pThisCC The VMMDev ring-3 instance data.
1509 * @param pReqHdr The header of the request to handle.
1510 */
1511static int vmmdevReqHandler_GetDisplayChangeRequest2(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC,
1512 VMMDevRequestHeader *pReqHdr)
1513{
1514 VMMDevDisplayChangeRequest2 *pReq = (VMMDevDisplayChangeRequest2 *)pReqHdr;
1515 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1516
1517 DISPLAYCHANGEREQUEST *pDispRequest = NULL;
1518
1519 if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
1520 {
1521 /* Select a pending request to report. */
1522 unsigned i;
1523 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1524 {
1525 if (pThis->displayChangeData.aRequests[i].fPending)
1526 {
1527 pDispRequest = &pThis->displayChangeData.aRequests[i];
1528 /* Remember which request should be reported. */
1529 pThis->displayChangeData.iCurrentMonitor = i;
1530 Log3(("VMMDev: will report pending request for %u\n", i));
1531 break;
1532 }
1533 }
1534
1535 /* Check if there are more pending requests. */
1536 i++;
1537 for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1538 {
1539 if (pThis->displayChangeData.aRequests[i].fPending)
1540 {
1541 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1542 Log3(("VMMDev: another pending at %u\n", i));
1543 break;
1544 }
1545 }
1546
1547 if (pDispRequest)
1548 {
1549 /* Current request has been read at least once. */
1550 pDispRequest->fPending = false;
1551
1552 /* Remember which resolution the client has queried, subsequent reads
1553 * will return the same values. */
1554 pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
1555 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1556 }
1557 else
1558 {
1559 Log3(("VMMDev: no pending request!!!\n"));
1560 }
1561 }
1562
1563 if (!pDispRequest)
1564 {
1565 Log3(("VMMDev: default to %d\n", pThis->displayChangeData.iCurrentMonitor));
1566 pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
1567 }
1568
1569 /* If not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1570 * read the last valid video mode hint. This happens when the guest X server
1571 * determines the initial mode. */
1572 VMMDevDisplayDef const *pDisplayDef = pThis->displayChangeData.fGuestSentChangeEventAck ?
1573 &pDispRequest->lastReadDisplayChangeRequest :
1574 &pDispRequest->displayChangeRequest;
1575 pReq->xres = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_CX) ? pDisplayDef->cx : 0;
1576 pReq->yres = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_CY) ? pDisplayDef->cy : 0;
1577 pReq->bpp = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_BPP) ? pDisplayDef->cBitsPerPixel : 0;
1578 pReq->display = pDisplayDef->idDisplay;
1579
1580 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
1581 pReq->xres, pReq->yres, pReq->bpp, pReq->display));
1582
1583 return VINF_SUCCESS;
1584}
1585
1586
1587/**
1588 * Handles VMMDevReq_GetDisplayChangeRequestEx.
1589 *
1590 * @returns VBox status code that the guest should see.
1591 * @param pDevIns The device instance.
1592 * @param pThis The VMMDev shared instance data.
1593 * @param pThisCC The VMMDev ring-3 instance data.
1594 * @param pReqHdr The header of the request to handle.
1595 */
1596static int vmmdevReqHandler_GetDisplayChangeRequestEx(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC,
1597 VMMDevRequestHeader *pReqHdr)
1598{
1599 VMMDevDisplayChangeRequestEx *pReq = (VMMDevDisplayChangeRequestEx *)pReqHdr;
1600 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1601
1602 DISPLAYCHANGEREQUEST *pDispRequest = NULL;
1603
1604 if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
1605 {
1606 /* Select a pending request to report. */
1607 unsigned i;
1608 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1609 {
1610 if (pThis->displayChangeData.aRequests[i].fPending)
1611 {
1612 pDispRequest = &pThis->displayChangeData.aRequests[i];
1613 /* Remember which request should be reported. */
1614 pThis->displayChangeData.iCurrentMonitor = i;
1615 Log3(("VMMDev: will report pending request for %d\n",
1616 i));
1617 break;
1618 }
1619 }
1620
1621 /* Check if there are more pending requests. */
1622 i++;
1623 for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
1624 {
1625 if (pThis->displayChangeData.aRequests[i].fPending)
1626 {
1627 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1628 Log3(("VMMDev: another pending at %d\n",
1629 i));
1630 break;
1631 }
1632 }
1633
1634 if (pDispRequest)
1635 {
1636 /* Current request has been read at least once. */
1637 pDispRequest->fPending = false;
1638
1639 /* Remember which resolution the client has queried, subsequent reads
1640 * will return the same values. */
1641 pDispRequest->lastReadDisplayChangeRequest = pDispRequest->displayChangeRequest;
1642 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1643 }
1644 else
1645 {
1646 Log3(("VMMDev: no pending request!!!\n"));
1647 }
1648 }
1649
1650 if (!pDispRequest)
1651 {
1652 Log3(("VMMDev: default to %d\n",
1653 pThis->displayChangeData.iCurrentMonitor));
1654 pDispRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
1655 }
1656
1657 /* If not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1658 * read the last valid video mode hint. This happens when the guest X server
1659 * determines the initial mode. */
1660 VMMDevDisplayDef const *pDisplayDef = pThis->displayChangeData.fGuestSentChangeEventAck ?
1661 &pDispRequest->lastReadDisplayChangeRequest :
1662 &pDispRequest->displayChangeRequest;
1663 pReq->xres = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_CX) ? pDisplayDef->cx : 0;
1664 pReq->yres = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_CY) ? pDisplayDef->cy : 0;
1665 pReq->bpp = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_BPP) ? pDisplayDef->cBitsPerPixel : 0;
1666 pReq->display = pDisplayDef->idDisplay;
1667 pReq->cxOrigin = pDisplayDef->xOrigin;
1668 pReq->cyOrigin = pDisplayDef->yOrigin;
1669 pReq->fEnabled = !RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_DISABLED);
1670 pReq->fChangeOrigin = RT_BOOL(pDisplayDef->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN);
1671
1672 Log(("VMMDevEx: returning display change request xres = %d, yres = %d, bpp = %d id %d xPos = %d, yPos = %d & Enabled=%d\n",
1673 pReq->xres, pReq->yres, pReq->bpp, pReq->display, pReq->cxOrigin, pReq->cyOrigin, pReq->fEnabled));
1674
1675 return VINF_SUCCESS;
1676}
1677
1678
1679/**
1680 * Handles VMMDevReq_GetDisplayChangeRequestMulti.
1681 *
1682 * @returns VBox status code that the guest should see.
1683 * @param pThis The VMMDev shared instance data.
1684 * @param pReqHdr The header of the request to handle.
1685 */
1686static int vmmdevReqHandler_GetDisplayChangeRequestMulti(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
1687{
1688 VMMDevDisplayChangeRequestMulti *pReq = (VMMDevDisplayChangeRequestMulti *)pReqHdr;
1689 unsigned i;
1690
1691 ASSERT_GUEST_MSG_RETURN(pReq->header.size >= sizeof(*pReq),
1692 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1693 RT_UNTRUSTED_VALIDATED_FENCE();
1694
1695 uint32_t const cDisplays = pReq->cDisplays;
1696 ASSERT_GUEST_MSG_RETURN(cDisplays > 0 && cDisplays <= RT_ELEMENTS(pThis->displayChangeData.aRequests),
1697 ("cDisplays %u\n", cDisplays), VERR_INVALID_PARAMETER);
1698 RT_UNTRUSTED_VALIDATED_FENCE();
1699
1700 ASSERT_GUEST_MSG_RETURN(pReq->header.size >= sizeof(*pReq) + (cDisplays - 1) * sizeof(VMMDevDisplayDef),
1701 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1702 RT_UNTRUSTED_VALIDATED_FENCE();
1703
1704 if (pReq->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
1705 {
1706 uint32_t cDisplaysOut = 0;
1707 /* Remember which resolution the client has queried, subsequent reads
1708 * will return the same values. */
1709 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); ++i)
1710 {
1711 DISPLAYCHANGEREQUEST *pDCR = &pThis->displayChangeData.aRequests[i];
1712
1713 pDCR->lastReadDisplayChangeRequest = pDCR->displayChangeRequest;
1714
1715 if (pDCR->fPending)
1716 {
1717 if (cDisplaysOut < cDisplays)
1718 pReq->aDisplays[cDisplaysOut] = pDCR->lastReadDisplayChangeRequest;
1719
1720 cDisplaysOut++;
1721 pDCR->fPending = false;
1722 }
1723 }
1724
1725 pReq->cDisplays = cDisplaysOut;
1726 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1727 }
1728 else
1729 {
1730 /* Fill the guest request with monitor layout data. */
1731 for (i = 0; i < cDisplays; ++i)
1732 {
1733 /* If not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1734 * read the last valid video mode hint. This happens when the guest X server
1735 * determines the initial mode. */
1736 DISPLAYCHANGEREQUEST const *pDCR = &pThis->displayChangeData.aRequests[i];
1737 VMMDevDisplayDef const *pDisplayDef = pThis->displayChangeData.fGuestSentChangeEventAck ?
1738 &pDCR->lastReadDisplayChangeRequest :
1739 &pDCR->displayChangeRequest;
1740 pReq->aDisplays[i] = *pDisplayDef;
1741 }
1742 }
1743
1744 Log(("VMMDev: returning multimonitor display change request cDisplays %d\n", cDisplays));
1745
1746 return VINF_SUCCESS;
1747}
1748
1749
1750/**
1751 * Handles VMMDevReq_VideoModeSupported.
1752 *
1753 * Query whether the given video mode is supported.
1754 *
1755 * @returns VBox status code that the guest should see.
1756 * @param pThisCC The VMMDev ring-3 instance data.
1757 * @param pReqHdr The header of the request to handle.
1758 */
1759static int vmmdevReqHandler_VideoModeSupported(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1760{
1761 VMMDevVideoModeSupportedRequest *pReq = (VMMDevVideoModeSupportedRequest *)pReqHdr;
1762 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1763
1764 /* forward the call */
1765 return pThisCC->pDrv->pfnVideoModeSupported(pThisCC->pDrv,
1766 0, /* primary screen. */
1767 pReq->width,
1768 pReq->height,
1769 pReq->bpp,
1770 &pReq->fSupported);
1771}
1772
1773
1774/**
1775 * Handles VMMDevReq_VideoModeSupported2.
1776 *
1777 * Query whether the given video mode is supported for a specific display
1778 *
1779 * @returns VBox status code that the guest should see.
1780 * @param pThisCC The VMMDev ring-3 instance data.
1781 * @param pReqHdr The header of the request to handle.
1782 */
1783static int vmmdevReqHandler_VideoModeSupported2(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1784{
1785 VMMDevVideoModeSupportedRequest2 *pReq = (VMMDevVideoModeSupportedRequest2 *)pReqHdr;
1786 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1787
1788 /* forward the call */
1789 return pThisCC->pDrv->pfnVideoModeSupported(pThisCC->pDrv,
1790 pReq->display,
1791 pReq->width,
1792 pReq->height,
1793 pReq->bpp,
1794 &pReq->fSupported);
1795}
1796
1797
1798
1799/**
1800 * Handles VMMDevReq_GetHeightReduction.
1801 *
1802 * @returns VBox status code that the guest should see.
1803 * @param pThisCC The VMMDev ring-3 instance data.
1804 * @param pReqHdr The header of the request to handle.
1805 */
1806static int vmmdevReqHandler_GetHeightReduction(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1807{
1808 VMMDevGetHeightReductionRequest *pReq = (VMMDevGetHeightReductionRequest *)pReqHdr;
1809 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1810
1811 /* forward the call */
1812 return pThisCC->pDrv->pfnGetHeightReduction(pThisCC->pDrv, &pReq->heightReduction);
1813}
1814
1815
1816/**
1817 * Handles VMMDevReq_AcknowledgeEvents.
1818 *
1819 * @returns VBox status code that the guest should see.
1820 * @param pDevIns The device instance.
1821 * @param pThis The VMMDev shared instance data.
1822 * @param pThisCC The VMMDev ring-3 instance data.
1823 * @param pReqHdr The header of the request to handle.
1824 */
1825static int vmmdevReqHandler_AcknowledgeEvents(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1826{
1827 VMMDevEvents *pReq = (VMMDevEvents *)pReqHdr;
1828 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1829 STAM_REL_COUNTER_INC(&pThis->StatSlowIrqAck);
1830
1831 if (!VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
1832 {
1833 /*
1834 * Note! This code is duplicated in vmmdevFastRequestIrqAck.
1835 */
1836 if (pThis->fNewGuestFilterMaskValid)
1837 {
1838 pThis->fNewGuestFilterMaskValid = false;
1839 pThis->fGuestFilterMask = pThis->fNewGuestFilterMask;
1840 }
1841
1842 pReq->events = pThis->fHostEventFlags & pThis->fGuestFilterMask;
1843
1844 pThis->fHostEventFlags &= ~pThis->fGuestFilterMask;
1845 pThisCC->CTX_SUFF(pVMMDevRAM)->V.V1_04.fHaveEvents = false;
1846
1847 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 0);
1848 }
1849 else
1850 vmmdevSetIRQ_Legacy(pDevIns, pThis, pThisCC);
1851 return VINF_SUCCESS;
1852}
1853
1854
1855/**
1856 * Handles VMMDevReq_CtlGuestFilterMask.
1857 *
1858 * @returns VBox status code that the guest should see.
1859 * @param pDevIns The device instance.
1860 * @param pThis The VMMDev shared instance data.
1861 * @param pThisCC The VMMDev ring-3 instance data.
1862 * @param pReqHdr The header of the request to handle.
1863 */
1864static int vmmdevReqHandler_CtlGuestFilterMask(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1865{
1866 VMMDevCtlGuestFilterMask *pReq = (VMMDevCtlGuestFilterMask *)pReqHdr;
1867 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
1868
1869 LogRelFlow(("VMMDev: vmmdevReqHandler_CtlGuestFilterMask: OR mask: %#x, NOT mask: %#x\n", pReq->u32OrMask, pReq->u32NotMask));
1870
1871 /* HGCM event notification is enabled by the VMMDev device
1872 * automatically when any HGCM command is issued. The guest
1873 * cannot disable these notifications. */
1874 VMMDevCtlSetGuestFilterMask(pDevIns, pThis, pThisCC, pReq->u32OrMask, pReq->u32NotMask & ~VMMDEV_EVENT_HGCM);
1875 return VINF_SUCCESS;
1876}
1877
1878#ifdef VBOX_WITH_HGCM
1879
1880/**
1881 * Handles VMMDevReq_HGCMConnect.
1882 *
1883 * @returns VBox status code that the guest should see.
1884 * @param pDevIns The device instance.
1885 * @param pThis The VMMDev shared instance data.
1886 * @param pThisCC The VMMDev ring-3 instance data.
1887 * @param pReqHdr The header of the request to handle.
1888 * @param GCPhysReqHdr The guest physical address of the request header.
1889 */
1890static int vmmdevReqHandler_HGCMConnect(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC,
1891 VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
1892{
1893 VMMDevHGCMConnect *pReq = (VMMDevHGCMConnect *)pReqHdr;
1894 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this is >= ... */
1895
1896 if (pThisCC->pHGCMDrv)
1897 {
1898 Log(("VMMDevReq_HGCMConnect\n"));
1899 return vmmdevR3HgcmConnect(pDevIns, pThis, pThisCC, pReq, GCPhysReqHdr);
1900 }
1901
1902 Log(("VMMDevReq_HGCMConnect: HGCM Connector is NULL!\n"));
1903 return VERR_NOT_SUPPORTED;
1904}
1905
1906
1907/**
1908 * Handles VMMDevReq_HGCMDisconnect.
1909 *
1910 * @returns VBox status code that the guest should see.
1911 * @param pDevIns The device instance.
1912 * @param pThis The VMMDev shared instance data.
1913 * @param pThisCC The VMMDev ring-3 instance data.
1914 * @param pReqHdr The header of the request to handle.
1915 * @param GCPhysReqHdr The guest physical address of the request header.
1916 */
1917static int vmmdevReqHandler_HGCMDisconnect(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC,
1918 VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
1919{
1920 VMMDevHGCMDisconnect *pReq = (VMMDevHGCMDisconnect *)pReqHdr;
1921 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
1922
1923 if (pThisCC->pHGCMDrv)
1924 {
1925 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1926 return vmmdevR3HgcmDisconnect(pDevIns, pThis, pThisCC, pReq, GCPhysReqHdr);
1927 }
1928
1929 Log(("VMMDevReq_VMMDevHGCMDisconnect: HGCM Connector is NULL!\n"));
1930 return VERR_NOT_SUPPORTED;
1931}
1932
1933
1934/**
1935 * Handles VMMDevReq_HGCMCall32 and VMMDevReq_HGCMCall64.
1936 *
1937 * @returns VBox status code that the guest should see.
1938 * @param pDevIns The device instance.
1939 * @param pThis The VMMDev shared instance data.
1940 * @param pThisCC The VMMDev ring-3 instance data.
1941 * @param pReqHdr The header of the request to handle.
1942 * @param GCPhysReqHdr The guest physical address of the request header.
1943 * @param tsArrival The STAM_GET_TS() value when the request arrived.
1944 * @param ppLock Pointer to the lock info pointer (latter can be
1945 * NULL). Set to NULL if HGCM takes lock ownership.
1946 */
1947static int vmmdevReqHandler_HGCMCall(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr,
1948 RTGCPHYS GCPhysReqHdr, uint64_t tsArrival, PVMMDEVREQLOCK *ppLock)
1949{
1950 VMMDevHGCMCall *pReq = (VMMDevHGCMCall *)pReqHdr;
1951 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER);
1952
1953 if (pThisCC->pHGCMDrv)
1954 {
1955 Log2(("VMMDevReq_HGCMCall: sizeof(VMMDevHGCMRequest) = %04X\n", sizeof(VMMDevHGCMCall)));
1956 Log2(("%.*Rhxd\n", pReq->header.header.size, pReq));
1957
1958 return vmmdevR3HgcmCall(pDevIns, pThis, pThisCC, pReq, pReq->header.header.size, GCPhysReqHdr,
1959 pReq->header.header.requestType, tsArrival, ppLock);
1960 }
1961
1962 Log(("VMMDevReq_HGCMCall: HGCM Connector is NULL!\n"));
1963 return VERR_NOT_SUPPORTED;
1964}
1965
1966/**
1967 * Handles VMMDevReq_HGCMCancel.
1968 *
1969 * @returns VBox status code that the guest should see.
1970 * @param pThisCC The VMMDev ring-3 instance data.
1971 * @param pReqHdr The header of the request to handle.
1972 * @param GCPhysReqHdr The guest physical address of the request header.
1973 */
1974static int vmmdevReqHandler_HGCMCancel(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr, RTGCPHYS GCPhysReqHdr)
1975{
1976 VMMDevHGCMCancel *pReq = (VMMDevHGCMCancel *)pReqHdr;
1977 AssertMsgReturn(pReq->header.header.size >= sizeof(*pReq), ("%u\n", pReq->header.header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
1978
1979 if (pThisCC->pHGCMDrv)
1980 {
1981 Log(("VMMDevReq_VMMDevHGCMCancel\n"));
1982 return vmmdevR3HgcmCancel(pThisCC, pReq, GCPhysReqHdr);
1983 }
1984
1985 Log(("VMMDevReq_VMMDevHGCMCancel: HGCM Connector is NULL!\n"));
1986 return VERR_NOT_SUPPORTED;
1987}
1988
1989
1990/**
1991 * Handles VMMDevReq_HGCMCancel2.
1992 *
1993 * @returns VBox status code that the guest should see.
1994 * @param pThisCC The VMMDev ring-3 instance data.
1995 * @param pReqHdr The header of the request to handle.
1996 */
1997static int vmmdevReqHandler_HGCMCancel2(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
1998{
1999 VMMDevHGCMCancel2 *pReq = (VMMDevHGCMCancel2 *)pReqHdr;
2000 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
2001
2002 if (pThisCC->pHGCMDrv)
2003 {
2004 Log(("VMMDevReq_HGCMCancel2\n"));
2005 return vmmdevR3HgcmCancel2(pThisCC, pReq->physReqToCancel);
2006 }
2007
2008 Log(("VMMDevReq_HGCMCancel2: HGCM Connector is NULL!\n"));
2009 return VERR_NOT_SUPPORTED;
2010}
2011
2012#endif /* VBOX_WITH_HGCM */
2013
2014
2015/**
2016 * Handles VMMDevReq_VideoAccelEnable.
2017 *
2018 * @returns VBox status code that the guest should see.
2019 * @param pThis The VMMDev shared instance data.
2020 * @param pThisCC The VMMDev ring-3 instance data.
2021 * @param pReqHdr The header of the request to handle.
2022 */
2023static int vmmdevReqHandler_VideoAccelEnable(PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2024{
2025 VMMDevVideoAccelEnable *pReq = (VMMDevVideoAccelEnable *)pReqHdr;
2026 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
2027
2028 if (!pThisCC->pDrv)
2029 {
2030 Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!\n"));
2031 return VERR_NOT_SUPPORTED;
2032 }
2033
2034 if (pReq->cbRingBuffer != VMMDEV_VBVA_RING_BUFFER_SIZE)
2035 {
2036 /* The guest driver seems compiled with different headers. */
2037 LogRelMax(16,("VMMDevReq_VideoAccelEnable guest ring buffer size %#x, should be %#x!!\n", pReq->cbRingBuffer, VMMDEV_VBVA_RING_BUFFER_SIZE));
2038 return VERR_INVALID_PARAMETER;
2039 }
2040
2041 /* The request is correct. */
2042 pReq->fu32Status |= VBVA_F_STATUS_ACCEPTED;
2043
2044 LogFlow(("VMMDevReq_VideoAccelEnable pReq->u32Enable = %d\n", pReq->u32Enable));
2045
2046 int rc = pReq->u32Enable
2047 ? pThisCC->pDrv->pfnVideoAccelEnable(pThisCC->pDrv, true, &pThisCC->pVMMDevRAMR3->vbvaMemory)
2048 : pThisCC->pDrv->pfnVideoAccelEnable(pThisCC->pDrv, false, NULL);
2049
2050 if ( pReq->u32Enable
2051 && RT_SUCCESS(rc))
2052 {
2053 pReq->fu32Status |= VBVA_F_STATUS_ENABLED;
2054
2055 /* Remember that guest successfully enabled acceleration.
2056 * We need to reestablish it on restoring the VM from saved state.
2057 */
2058 pThis->u32VideoAccelEnabled = 1;
2059 }
2060 else
2061 {
2062 /* The acceleration was not enabled. Remember that. */
2063 pThis->u32VideoAccelEnabled = 0;
2064 }
2065 return VINF_SUCCESS;
2066}
2067
2068
2069/**
2070 * Handles VMMDevReq_VideoAccelFlush.
2071 *
2072 * @returns VBox status code that the guest should see.
2073 * @param pThisCC The VMMDev ring-3 instance data.
2074 * @param pReqHdr The header of the request to handle.
2075 */
2076static int vmmdevReqHandler_VideoAccelFlush(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2077{
2078 VMMDevVideoAccelFlush *pReq = (VMMDevVideoAccelFlush *)pReqHdr;
2079 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER); /** @todo Not sure why this >= ... */
2080
2081 if (!pThisCC->pDrv)
2082 {
2083 Log(("VMMDevReq_VideoAccelFlush: Connector is NULL!!!\n"));
2084 return VERR_NOT_SUPPORTED;
2085 }
2086
2087 pThisCC->pDrv->pfnVideoAccelFlush(pThisCC->pDrv);
2088 return VINF_SUCCESS;
2089}
2090
2091
2092/**
2093 * Handles VMMDevReq_VideoSetVisibleRegion.
2094 *
2095 * @returns VBox status code that the guest should see.
2096 * @param pThisCC The VMMDev ring-3 instance data.
2097 * @param pReqHdr The header of the request to handle.
2098 */
2099static int vmmdevReqHandler_VideoSetVisibleRegion(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2100{
2101 VMMDevVideoSetVisibleRegion *pReq = (VMMDevVideoSetVisibleRegion *)pReqHdr;
2102 AssertMsgReturn(pReq->header.size + sizeof(RTRECT) >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2103
2104 if (!pThisCC->pDrv)
2105 {
2106 Log(("VMMDevReq_VideoSetVisibleRegion: Connector is NULL!!!\n"));
2107 return VERR_NOT_SUPPORTED;
2108 }
2109
2110 if ( pReq->cRect > _1M /* restrict to sane range */
2111 || pReq->header.size != sizeof(VMMDevVideoSetVisibleRegion) + pReq->cRect * sizeof(RTRECT) - sizeof(RTRECT))
2112 {
2113 Log(("VMMDevReq_VideoSetVisibleRegion: cRects=%#x doesn't match size=%#x or is out of bounds\n",
2114 pReq->cRect, pReq->header.size));
2115 return VERR_INVALID_PARAMETER;
2116 }
2117
2118 Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", pReq->cRect));
2119 /* forward the call */
2120 return pThisCC->pDrv->pfnSetVisibleRegion(pThisCC->pDrv, pReq->cRect, &pReq->Rect);
2121}
2122
2123/**
2124 * Handles VMMDevReq_VideoUpdateMonitorPositions.
2125 *
2126 * @returns VBox status code that the guest should see.
2127 * @param pThisCC The VMMDev ring-3 instance data.
2128 * @param pReqHdr The header of the request to handle.
2129 */
2130static int vmmdevReqHandler_VideoUpdateMonitorPositions(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2131{
2132 VMMDevVideoUpdateMonitorPositions *pReq = (VMMDevVideoUpdateMonitorPositions *)pReqHdr;
2133 AssertMsgReturn(pReq->header.size + sizeof(RTRECT) >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2134 if (!pThisCC->pDrv)
2135 {
2136 Log(("VMMDevReq_VideoUpdateMonitorPositions: Connector is NULL!!!\n"));
2137 return VERR_NOT_SUPPORTED;
2138 }
2139 if ( pReq->cPositions > _1M /* restrict to sane range */
2140 || pReq->header.size != sizeof(VMMDevVideoUpdateMonitorPositions) + pReq->cPositions * sizeof(RTPOINT) - sizeof(RTPOINT))
2141 {
2142 Log(("VMMDevReq_VideoUpdateMonitorPositions: cRects=%#x doesn't match size=%#x or is out of bounds\n",
2143 pReq->cPositions, pReq->header.size));
2144 return VERR_INVALID_PARAMETER;
2145 }
2146 Log(("VMMDevReq_VideoUpdateMonitorPositions %d rectangles\n", pReq->cPositions));
2147 /* forward the call */
2148 return pThisCC->pDrv->pfnUpdateMonitorPositions(pThisCC->pDrv, pReq->cPositions, &(pReq->aPositions[0]));
2149}
2150
2151/**
2152 * Handles VMMDevReq_GetSeamlessChangeRequest.
2153 *
2154 * @returns VBox status code that the guest should see.
2155 * @param pThis The VMMDev shared instance data.
2156 * @param pReqHdr The header of the request to handle.
2157 */
2158static int vmmdevReqHandler_GetSeamlessChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2159{
2160 VMMDevSeamlessChangeRequest *pReq = (VMMDevSeamlessChangeRequest *)pReqHdr;
2161 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2162
2163 /* just pass on the information */
2164 Log(("VMMDev: returning seamless change request mode=%d\n", pThis->fSeamlessEnabled));
2165 if (pThis->fSeamlessEnabled)
2166 pReq->mode = VMMDev_Seamless_Visible_Region;
2167 else
2168 pReq->mode = VMMDev_Seamless_Disabled;
2169
2170 if (pReq->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
2171 {
2172 /* Remember which mode the client has queried. */
2173 pThis->fLastSeamlessEnabled = pThis->fSeamlessEnabled;
2174 }
2175
2176 return VINF_SUCCESS;
2177}
2178
2179
2180/**
2181 * Handles VMMDevReq_GetVRDPChangeRequest.
2182 *
2183 * @returns VBox status code that the guest should see.
2184 * @param pThis The VMMDev shared instance data.
2185 * @param pReqHdr The header of the request to handle.
2186 */
2187static int vmmdevReqHandler_GetVRDPChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2188{
2189 VMMDevVRDPChangeRequest *pReq = (VMMDevVRDPChangeRequest *)pReqHdr;
2190 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2191
2192 /* just pass on the information */
2193 Log(("VMMDev: returning VRDP status %d level %d\n", pThis->fVRDPEnabled, pThis->uVRDPExperienceLevel));
2194
2195 pReq->u8VRDPActive = pThis->fVRDPEnabled;
2196 pReq->u32VRDPExperienceLevel = pThis->uVRDPExperienceLevel;
2197
2198 return VINF_SUCCESS;
2199}
2200
2201
2202/**
2203 * Handles VMMDevReq_GetMemBalloonChangeRequest.
2204 *
2205 * @returns VBox status code that the guest should see.
2206 * @param pThis The VMMDev shared instance data.
2207 * @param pReqHdr The header of the request to handle.
2208 */
2209static int vmmdevReqHandler_GetMemBalloonChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2210{
2211 VMMDevGetMemBalloonChangeRequest *pReq = (VMMDevGetMemBalloonChangeRequest *)pReqHdr;
2212 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2213
2214 /* just pass on the information */
2215 Log(("VMMDev: returning memory balloon size =%d\n", pThis->cMbMemoryBalloon));
2216 pReq->cBalloonChunks = pThis->cMbMemoryBalloon;
2217 pReq->cPhysMemChunks = pThis->cbGuestRAM / (uint64_t)_1M;
2218
2219 if (pReq->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
2220 {
2221 /* Remember which mode the client has queried. */
2222 pThis->cMbMemoryBalloonLast = pThis->cMbMemoryBalloon;
2223 }
2224
2225 return VINF_SUCCESS;
2226}
2227
2228
2229/**
2230 * Handles VMMDevReq_ChangeMemBalloon.
2231 *
2232 * @returns VBox status code that the guest should see.
2233 * @param pDevIns The device instance.
2234 * @param pThis The VMMDev shared instance data.
2235 * @param pReqHdr The header of the request to handle.
2236 */
2237static int vmmdevReqHandler_ChangeMemBalloon(PPDMDEVINS pDevIns, PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2238{
2239 VMMDevChangeMemBalloon *pReq = (VMMDevChangeMemBalloon *)pReqHdr;
2240 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2241 AssertMsgReturn(pReq->cPages == VMMDEV_MEMORY_BALLOON_CHUNK_PAGES, ("%u\n", pReq->cPages), VERR_INVALID_PARAMETER);
2242 AssertMsgReturn(pReq->header.size == (uint32_t)RT_UOFFSETOF_DYN(VMMDevChangeMemBalloon, aPhysPage[pReq->cPages]),
2243 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2244
2245 Log(("VMMDevReq_ChangeMemBalloon\n"));
2246 int rc = PDMDevHlpPhysChangeMemBalloon(pDevIns, !!pReq->fInflate, pReq->cPages, pReq->aPhysPage);
2247 if (pReq->fInflate)
2248 STAM_REL_U32_INC(&pThis->StatMemBalloonChunks);
2249 else
2250 STAM_REL_U32_DEC(&pThis->StatMemBalloonChunks);
2251 return rc;
2252}
2253
2254
2255/**
2256 * Handles VMMDevReq_GetStatisticsChangeRequest.
2257 *
2258 * @returns VBox status code that the guest should see.
2259 * @param pThis The VMMDev shared instance data.
2260 * @param pReqHdr The header of the request to handle.
2261 */
2262static int vmmdevReqHandler_GetStatisticsChangeRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2263{
2264 VMMDevGetStatisticsChangeRequest *pReq = (VMMDevGetStatisticsChangeRequest *)pReqHdr;
2265 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2266
2267 Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
2268 /* just pass on the information */
2269 Log(("VMMDev: returning statistics interval %d seconds\n", pThis->cSecsStatInterval));
2270 pReq->u32StatInterval = pThis->cSecsStatInterval;
2271
2272 if (pReq->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
2273 {
2274 /* Remember which mode the client has queried. */
2275 pThis->cSecsLastStatInterval = pThis->cSecsStatInterval;
2276 }
2277
2278 return VINF_SUCCESS;
2279}
2280
2281
2282/**
2283 * Handles VMMDevReq_ReportGuestStats.
2284 *
2285 * @returns VBox status code that the guest should see.
2286 * @param pThisCC The VMMDev ring-3 instance data.
2287 * @param pReqHdr The header of the request to handle.
2288 */
2289static int vmmdevReqHandler_ReportGuestStats(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2290{
2291 VMMDevReportGuestStats *pReq = (VMMDevReportGuestStats *)pReqHdr;
2292 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2293
2294 Log(("VMMDevReq_ReportGuestStats\n"));
2295#ifdef LOG_ENABLED
2296 VBoxGuestStatistics *pGuestStats = &pReq->guestStats;
2297
2298 Log(("Current statistics:\n"));
2299 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
2300 Log(("CPU%u: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
2301
2302 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
2303 Log(("CPU%u: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
2304
2305 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
2306 Log(("CPU%u: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
2307
2308 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
2309 Log(("CPU%u: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
2310
2311 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
2312 Log(("CPU%u: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
2313
2314 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
2315 Log(("CPU%u: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
2316
2317 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
2318 Log(("CPU%u: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
2319
2320 /* Note that reported values are in pages; upper layers expect them in megabytes */
2321 Log(("CPU%u: Page size %-4d bytes\n", pGuestStats->u32CpuId, pGuestStats->u32PageSize));
2322 Assert(pGuestStats->u32PageSize == 4096);
2323
2324 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
2325 Log(("CPU%u: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/_4K)-1) / (_1M/_4K)));
2326
2327 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
2328 Log(("CPU%u: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/_4K)));
2329
2330 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
2331 Log(("CPU%u: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/_4K)));
2332
2333 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
2334 Log(("CPU%u: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/_4K)));
2335
2336 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
2337 Log(("CPU%u: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/_4K)));
2338
2339 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
2340 Log(("CPU%u: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/_4K)));
2341
2342 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
2343 Log(("CPU%u: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/_4K)));
2344
2345 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
2346 Log(("CPU%u: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/_4K)));
2347
2348 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
2349 Log(("CPU%u: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/_4K)));
2350 Log(("Statistics end *******************\n"));
2351#endif /* LOG_ENABLED */
2352
2353 /* forward the call */
2354 return pThisCC->pDrv->pfnReportStatistics(pThisCC->pDrv, &pReq->guestStats);
2355}
2356
2357
2358/**
2359 * Handles VMMDevReq_QueryCredentials.
2360 *
2361 * @returns VBox status code that the guest should see.
2362 * @param pThis The VMMDev shared instance data.
2363 * @param pThisCC The VMMDev ring-3 instance data.
2364 * @param pReqHdr The header of the request to handle.
2365 */
2366static int vmmdevReqHandler_QueryCredentials(PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2367{
2368 VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
2369 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2370 VMMDEVCREDS *pCredentials = pThisCC->pCredentials;
2371 AssertPtrReturn(pCredentials, VERR_NOT_SUPPORTED);
2372
2373 /* let's start by nulling out the data */
2374 RT_ZERO(pReq->szUserName);
2375 RT_ZERO(pReq->szPassword);
2376 RT_ZERO(pReq->szDomain);
2377
2378 /* should we return whether we got credentials for a logon? */
2379 if (pReq->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
2380 {
2381 if ( pCredentials->Logon.szUserName[0]
2382 || pCredentials->Logon.szPassword[0]
2383 || pCredentials->Logon.szDomain[0])
2384 pReq->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
2385 else
2386 pReq->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
2387 }
2388
2389 /* does the guest want to read logon credentials? */
2390 if (pReq->u32Flags & VMMDEV_CREDENTIALS_READ)
2391 {
2392 if (pCredentials->Logon.szUserName[0])
2393 RTStrCopy(pReq->szUserName, sizeof(pReq->szUserName), pCredentials->Logon.szUserName);
2394 if (pCredentials->Logon.szPassword[0])
2395 RTStrCopy(pReq->szPassword, sizeof(pReq->szPassword), pCredentials->Logon.szPassword);
2396 if (pCredentials->Logon.szDomain[0])
2397 RTStrCopy(pReq->szDomain, sizeof(pReq->szDomain), pCredentials->Logon.szDomain);
2398 if (!pCredentials->Logon.fAllowInteractiveLogon)
2399 pReq->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
2400 else
2401 pReq->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
2402 }
2403
2404 if (!pThis->fKeepCredentials)
2405 {
2406 /* does the caller want us to destroy the logon credentials? */
2407 if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
2408 {
2409 RT_ZERO(pCredentials->Logon.szUserName);
2410 RT_ZERO(pCredentials->Logon.szPassword);
2411 RT_ZERO(pCredentials->Logon.szDomain);
2412 }
2413 }
2414
2415 /* does the guest want to read credentials for verification? */
2416 if (pReq->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
2417 {
2418 if (pCredentials->Judge.szUserName[0])
2419 RTStrCopy(pReq->szUserName, sizeof(pReq->szUserName), pCredentials->Judge.szUserName);
2420 if (pCredentials->Judge.szPassword[0])
2421 RTStrCopy(pReq->szPassword, sizeof(pReq->szPassword), pCredentials->Judge.szPassword);
2422 if (pCredentials->Judge.szDomain[0])
2423 RTStrCopy(pReq->szDomain, sizeof(pReq->szDomain), pCredentials->Judge.szDomain);
2424 }
2425
2426 /* does the caller want us to destroy the judgement credentials? */
2427 if (pReq->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
2428 {
2429 RT_ZERO(pCredentials->Judge.szUserName);
2430 RT_ZERO(pCredentials->Judge.szPassword);
2431 RT_ZERO(pCredentials->Judge.szDomain);
2432 }
2433
2434 return VINF_SUCCESS;
2435}
2436
2437
2438/**
2439 * Handles VMMDevReq_ReportCredentialsJudgement.
2440 *
2441 * @returns VBox status code that the guest should see.
2442 * @param pThisCC The VMMDev ring-3 instance data.
2443 * @param pReqHdr The header of the request to handle.
2444 */
2445static int vmmdevReqHandler_ReportCredentialsJudgement(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2446{
2447 VMMDevCredentials *pReq = (VMMDevCredentials *)pReqHdr;
2448 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2449
2450 /* what does the guest think about the credentials? (note: the order is important here!) */
2451 if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
2452 pThisCC->pDrv->pfnSetCredentialsJudgementResult(pThisCC->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
2453 else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
2454 pThisCC->pDrv->pfnSetCredentialsJudgementResult(pThisCC->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
2455 else if (pReq->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
2456 pThisCC->pDrv->pfnSetCredentialsJudgementResult(pThisCC->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
2457 else
2458 {
2459 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", pReq->u32Flags));
2460 /** @todo why don't we return VERR_INVALID_PARAMETER to the guest? */
2461 }
2462
2463 return VINF_SUCCESS;
2464}
2465
2466
2467/**
2468 * Handles VMMDevReq_GetHostVersion.
2469 *
2470 * @returns VBox status code that the guest should see.
2471 * @param pReqHdr The header of the request to handle.
2472 * @since 3.1.0
2473 * @note The ring-0 VBoxGuestLib uses this to check whether
2474 * VMMDevHGCMParmType_PageList is supported.
2475 */
2476static int vmmdevReqHandler_GetHostVersion(VMMDevRequestHeader *pReqHdr)
2477{
2478 VMMDevReqHostVersion *pReq = (VMMDevReqHostVersion *)pReqHdr;
2479 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2480
2481 pReq->major = RTBldCfgVersionMajor();
2482 pReq->minor = RTBldCfgVersionMinor();
2483 pReq->build = RTBldCfgVersionBuild();
2484 pReq->revision = RTBldCfgRevision();
2485 pReq->features = VMMDEV_HVF_HGCM_PHYS_PAGE_LIST
2486 | VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
2487 | VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST
2488 | VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST
2489 | VMMDEV_HVF_FAST_IRQ_ACK;
2490 return VINF_SUCCESS;
2491}
2492
2493
2494/**
2495 * Handles VMMDevReq_GetCpuHotPlugRequest.
2496 *
2497 * @returns VBox status code that the guest should see.
2498 * @param pThis The VMMDev shared instance data.
2499 * @param pReqHdr The header of the request to handle.
2500 */
2501static int vmmdevReqHandler_GetCpuHotPlugRequest(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2502{
2503 VMMDevGetCpuHotPlugRequest *pReq = (VMMDevGetCpuHotPlugRequest *)pReqHdr;
2504 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2505
2506 pReq->enmEventType = pThis->enmCpuHotPlugEvent;
2507 pReq->idCpuCore = pThis->idCpuCore;
2508 pReq->idCpuPackage = pThis->idCpuPackage;
2509
2510 /* Clear the event */
2511 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_None;
2512 pThis->idCpuCore = UINT32_MAX;
2513 pThis->idCpuPackage = UINT32_MAX;
2514
2515 return VINF_SUCCESS;
2516}
2517
2518
2519/**
2520 * Handles VMMDevReq_SetCpuHotPlugStatus.
2521 *
2522 * @returns VBox status code that the guest should see.
2523 * @param pThis The VMMDev shared instance data.
2524 * @param pReqHdr The header of the request to handle.
2525 */
2526static int vmmdevReqHandler_SetCpuHotPlugStatus(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2527{
2528 VMMDevCpuHotPlugStatusRequest *pReq = (VMMDevCpuHotPlugStatusRequest *)pReqHdr;
2529 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2530
2531 if (pReq->enmStatusType == VMMDevCpuStatusType_Disable)
2532 pThis->fCpuHotPlugEventsEnabled = false;
2533 else if (pReq->enmStatusType == VMMDevCpuStatusType_Enable)
2534 pThis->fCpuHotPlugEventsEnabled = true;
2535 else
2536 return VERR_INVALID_PARAMETER;
2537 return VINF_SUCCESS;
2538}
2539
2540
2541#ifdef DEBUG
2542/**
2543 * Handles VMMDevReq_LogString.
2544 *
2545 * @returns VBox status code that the guest should see.
2546 * @param pReqHdr The header of the request to handle.
2547 */
2548static int vmmdevReqHandler_LogString(VMMDevRequestHeader *pReqHdr)
2549{
2550 VMMDevReqLogString *pReq = (VMMDevReqLogString *)pReqHdr;
2551 AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2552 AssertMsgReturn(pReq->szString[pReq->header.size - RT_UOFFSETOF(VMMDevReqLogString, szString) - 1] == '\0',
2553 ("not null terminated\n"), VERR_INVALID_PARAMETER);
2554
2555 LogIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("DEBUG LOG: %s", pReq->szString));
2556 return VINF_SUCCESS;
2557}
2558#endif /* DEBUG */
2559
2560/**
2561 * Handles VMMDevReq_GetSessionId.
2562 *
2563 * Get a unique "session" ID for this VM, where the ID will be different after each
2564 * start, reset or restore of the VM. This can be used for restore detection
2565 * inside the guest.
2566 *
2567 * @returns VBox status code that the guest should see.
2568 * @param pThis The VMMDev shared instance data.
2569 * @param pReqHdr The header of the request to handle.
2570 */
2571static int vmmdevReqHandler_GetSessionId(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2572{
2573 VMMDevReqSessionId *pReq = (VMMDevReqSessionId *)pReqHdr;
2574 AssertMsgReturn(pReq->header.size == sizeof(*pReq), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2575
2576 pReq->idSession = pThis->idSession;
2577 return VINF_SUCCESS;
2578}
2579
2580
2581#ifdef VBOX_WITH_PAGE_SHARING
2582
2583/**
2584 * Handles VMMDevReq_RegisterSharedModule.
2585 *
2586 * @returns VBox status code that the guest should see.
2587 * @param pDevIns The device instance.
2588 * @param pReqHdr The header of the request to handle.
2589 */
2590static int vmmdevReqHandler_RegisterSharedModule(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
2591{
2592 /*
2593 * Basic input validation (more done by GMM).
2594 */
2595 VMMDevSharedModuleRegistrationRequest *pReq = (VMMDevSharedModuleRegistrationRequest *)pReqHdr;
2596 AssertMsgReturn(pReq->header.size >= sizeof(VMMDevSharedModuleRegistrationRequest),
2597 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2598 AssertMsgReturn(pReq->header.size == RT_UOFFSETOF_DYN(VMMDevSharedModuleRegistrationRequest, aRegions[pReq->cRegions]),
2599 ("%u cRegions=%u\n", pReq->header.size, pReq->cRegions), VERR_INVALID_PARAMETER);
2600
2601 AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
2602 AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
2603 int rc = RTStrValidateEncoding(pReq->szName);
2604 AssertRCReturn(rc, rc);
2605 rc = RTStrValidateEncoding(pReq->szVersion);
2606 AssertRCReturn(rc, rc);
2607
2608 /*
2609 * Forward the request to the VMM.
2610 */
2611 return PDMDevHlpSharedModuleRegister(pDevIns, pReq->enmGuestOS, pReq->szName, pReq->szVersion,
2612 pReq->GCBaseAddr, pReq->cbModule, pReq->cRegions, pReq->aRegions);
2613}
2614
2615/**
2616 * Handles VMMDevReq_UnregisterSharedModule.
2617 *
2618 * @returns VBox status code that the guest should see.
2619 * @param pDevIns The device instance.
2620 * @param pReqHdr The header of the request to handle.
2621 */
2622static int vmmdevReqHandler_UnregisterSharedModule(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
2623{
2624 /*
2625 * Basic input validation.
2626 */
2627 VMMDevSharedModuleUnregistrationRequest *pReq = (VMMDevSharedModuleUnregistrationRequest *)pReqHdr;
2628 AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleUnregistrationRequest),
2629 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2630
2631 AssertReturn(RTStrEnd(pReq->szName, sizeof(pReq->szName)), VERR_INVALID_PARAMETER);
2632 AssertReturn(RTStrEnd(pReq->szVersion, sizeof(pReq->szVersion)), VERR_INVALID_PARAMETER);
2633 int rc = RTStrValidateEncoding(pReq->szName);
2634 AssertRCReturn(rc, rc);
2635 rc = RTStrValidateEncoding(pReq->szVersion);
2636 AssertRCReturn(rc, rc);
2637
2638 /*
2639 * Forward the request to the VMM.
2640 */
2641 return PDMDevHlpSharedModuleUnregister(pDevIns, pReq->szName, pReq->szVersion,
2642 pReq->GCBaseAddr, pReq->cbModule);
2643}
2644
2645/**
2646 * Handles VMMDevReq_CheckSharedModules.
2647 *
2648 * @returns VBox status code that the guest should see.
2649 * @param pDevIns The device instance.
2650 * @param pReqHdr The header of the request to handle.
2651 */
2652static int vmmdevReqHandler_CheckSharedModules(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
2653{
2654 VMMDevSharedModuleCheckRequest *pReq = (VMMDevSharedModuleCheckRequest *)pReqHdr;
2655 AssertMsgReturn(pReq->header.size == sizeof(VMMDevSharedModuleCheckRequest),
2656 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2657 return PDMDevHlpSharedModuleCheckAll(pDevIns);
2658}
2659
2660/**
2661 * Handles VMMDevReq_GetPageSharingStatus.
2662 *
2663 * @returns VBox status code that the guest should see.
2664 * @param pThisCC The VMMDev ring-3 instance data.
2665 * @param pReqHdr The header of the request to handle.
2666 */
2667static int vmmdevReqHandler_GetPageSharingStatus(PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr)
2668{
2669 VMMDevPageSharingStatusRequest *pReq = (VMMDevPageSharingStatusRequest *)pReqHdr;
2670 AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageSharingStatusRequest),
2671 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2672
2673 pReq->fEnabled = false;
2674 int rc = pThisCC->pDrv->pfnIsPageFusionEnabled(pThisCC->pDrv, &pReq->fEnabled);
2675 if (RT_FAILURE(rc))
2676 pReq->fEnabled = false;
2677 return VINF_SUCCESS;
2678}
2679
2680
2681/**
2682 * Handles VMMDevReq_DebugIsPageShared.
2683 *
2684 * @returns VBox status code that the guest should see.
2685 * @param pDevIns The device instance.
2686 * @param pReqHdr The header of the request to handle.
2687 */
2688static int vmmdevReqHandler_DebugIsPageShared(PPDMDEVINS pDevIns, VMMDevRequestHeader *pReqHdr)
2689{
2690 VMMDevPageIsSharedRequest *pReq = (VMMDevPageIsSharedRequest *)pReqHdr;
2691 AssertMsgReturn(pReq->header.size == sizeof(VMMDevPageIsSharedRequest),
2692 ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2693
2694 return PDMDevHlpSharedModuleGetPageState(pDevIns, pReq->GCPtrPage, &pReq->fShared, &pReq->uPageFlags);
2695}
2696
2697#endif /* VBOX_WITH_PAGE_SHARING */
2698
2699
2700/**
2701 * Handles VMMDevReq_WriteCoreDumpe
2702 *
2703 * @returns VBox status code that the guest should see.
2704 * @param pDevIns The device instance.
2705 * @param pThis The VMMDev shared instance data.
2706 * @param pReqHdr Pointer to the request header.
2707 */
2708static int vmmdevReqHandler_WriteCoreDump(PPDMDEVINS pDevIns, PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
2709{
2710 VMMDevReqWriteCoreDump *pReq = (VMMDevReqWriteCoreDump *)pReqHdr;
2711 AssertMsgReturn(pReq->header.size == sizeof(VMMDevReqWriteCoreDump), ("%u\n", pReq->header.size), VERR_INVALID_PARAMETER);
2712
2713 /*
2714 * Only available if explicitly enabled by the user.
2715 */
2716 if (!pThis->fGuestCoreDumpEnabled)
2717 return VERR_ACCESS_DENIED;
2718
2719 /*
2720 * User makes sure the directory exists before composing the path.
2721 */
2722 if (!RTDirExists(pThis->szGuestCoreDumpDir))
2723 return VERR_PATH_NOT_FOUND;
2724
2725 char szCorePath[RTPATH_MAX];
2726 RTStrCopy(szCorePath, sizeof(szCorePath), pThis->szGuestCoreDumpDir);
2727 RTPathAppend(szCorePath, sizeof(szCorePath), "VBox.core");
2728
2729 /*
2730 * Rotate existing cores based on number of additional cores to keep around.
2731 */
2732 if (pThis->cGuestCoreDumps > 0)
2733 for (int64_t i = pThis->cGuestCoreDumps - 1; i >= 0; i--)
2734 {
2735 char szFilePathOld[RTPATH_MAX];
2736 if (i == 0)
2737 RTStrCopy(szFilePathOld, sizeof(szFilePathOld), szCorePath);
2738 else
2739 RTStrPrintf(szFilePathOld, sizeof(szFilePathOld), "%s.%lld", szCorePath, i);
2740
2741 char szFilePathNew[RTPATH_MAX];
2742 RTStrPrintf(szFilePathNew, sizeof(szFilePathNew), "%s.%lld", szCorePath, i + 1);
2743 int vrc = RTFileMove(szFilePathOld, szFilePathNew, RTFILEMOVE_FLAGS_REPLACE);
2744 if (vrc == VERR_FILE_NOT_FOUND)
2745 RTFileDelete(szFilePathNew);
2746 }
2747
2748 /*
2749 * Write the core file.
2750 */
2751 return PDMDevHlpDBGFCoreWrite(pDevIns, szCorePath, true /*fReplaceFile*/);
2752}
2753
2754
2755/**
2756 * Sets request status to VINF_HGCM_ASYNC_EXECUTE.
2757 *
2758 * @param pDevIns The device instance.
2759 * @param GCPhysReqHdr The guest physical address of the request.
2760 * @param pLock Pointer to the request locking info. NULL if not
2761 * locked.
2762 */
2763DECLINLINE(void) vmmdevReqHdrSetHgcmAsyncExecute(PPDMDEVINS pDevIns, RTGCPHYS GCPhysReqHdr, PVMMDEVREQLOCK pLock)
2764{
2765 if (pLock)
2766 ((VMMDevRequestHeader volatile *)pLock->pvReq)->rc = VINF_HGCM_ASYNC_EXECUTE;
2767 else
2768 {
2769 int32_t rcReq = VINF_HGCM_ASYNC_EXECUTE;
2770 PDMDevHlpPhysWrite(pDevIns, GCPhysReqHdr + RT_UOFFSETOF(VMMDevRequestHeader, rc), &rcReq, sizeof(rcReq));
2771 }
2772}
2773
2774
2775/** @name VMMDEVREQDISP_POST_F_XXX - post dispatcher optimizations.
2776 * @{ */
2777#define VMMDEVREQDISP_POST_F_NO_WRITE_OUT RT_BIT_32(0)
2778/** @} */
2779
2780
2781/**
2782 * Dispatch the request to the appropriate handler function.
2783 *
2784 * @returns Port I/O handler exit code.
2785 * @param pDevIns The device instance.
2786 * @param pThis The VMMDev shared instance data.
2787 * @param pThisCC The VMMDev ring-3 instance data.
2788 * @param pReqHdr The request header (cached in host memory).
2789 * @param GCPhysReqHdr The guest physical address of the request (for
2790 * HGCM).
2791 * @param tsArrival The STAM_GET_TS() value when the request arrived.
2792 * @param pfPostOptimize HGCM optimizations, VMMDEVREQDISP_POST_F_XXX.
2793 * @param ppLock Pointer to the lock info pointer (latter can be
2794 * NULL). Set to NULL if HGCM takes lock ownership.
2795 */
2796static VBOXSTRICTRC vmmdevReqDispatcher(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr,
2797 RTGCPHYS GCPhysReqHdr, uint64_t tsArrival, uint32_t *pfPostOptimize,
2798 PVMMDEVREQLOCK *ppLock)
2799{
2800 int rcRet = VINF_SUCCESS;
2801 Assert(*pfPostOptimize == 0);
2802 switch (pReqHdr->requestType)
2803 {
2804 case VMMDevReq_ReportGuestInfo:
2805 pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo(pDevIns, pThis, pThisCC, pReqHdr);
2806 break;
2807
2808 case VMMDevReq_ReportGuestInfo2:
2809 pReqHdr->rc = vmmdevReqHandler_ReportGuestInfo2(pDevIns, pThis, pThisCC, pReqHdr);
2810 break;
2811
2812 case VMMDevReq_ReportGuestStatus:
2813 pReqHdr->rc = vmmdevReqHandler_ReportGuestStatus(pThis, pThisCC, pReqHdr);
2814 break;
2815
2816 case VMMDevReq_ReportGuestUserState:
2817 pReqHdr->rc = vmmdevReqHandler_ReportGuestUserState(pThisCC, pReqHdr);
2818 break;
2819
2820 case VMMDevReq_ReportGuestCapabilities:
2821 pReqHdr->rc = vmmdevReqHandler_ReportGuestCapabilities(pThis, pThisCC, pReqHdr);
2822 break;
2823
2824 case VMMDevReq_SetGuestCapabilities:
2825 pReqHdr->rc = vmmdevReqHandler_SetGuestCapabilities(pThis, pThisCC, pReqHdr);
2826 break;
2827
2828 case VMMDevReq_WriteCoreDump:
2829 pReqHdr->rc = vmmdevReqHandler_WriteCoreDump(pDevIns, pThis, pReqHdr);
2830 break;
2831
2832 case VMMDevReq_GetMouseStatus:
2833 pReqHdr->rc = vmmdevReqHandler_GetMouseStatus(pThis, pReqHdr);
2834 break;
2835
2836 case VMMDevReq_GetMouseStatusEx:
2837 pReqHdr->rc = vmmdevReqHandler_GetMouseStatusEx(pThis, pReqHdr);
2838 break;
2839
2840 case VMMDevReq_SetMouseStatus:
2841 pReqHdr->rc = vmmdevReqHandler_SetMouseStatus(pThis, pThisCC, pReqHdr);
2842 break;
2843
2844 case VMMDevReq_SetPointerShape:
2845 pReqHdr->rc = vmmdevReqHandler_SetPointerShape(pThis, pThisCC, pReqHdr);
2846 break;
2847
2848 case VMMDevReq_GetHostTime:
2849 pReqHdr->rc = vmmdevReqHandler_GetHostTime(pDevIns, pThis, pReqHdr);
2850 break;
2851
2852 case VMMDevReq_GetHypervisorInfo:
2853 pReqHdr->rc = vmmdevReqHandler_GetHypervisorInfo(pDevIns, pReqHdr);
2854 break;
2855
2856 case VMMDevReq_SetHypervisorInfo:
2857 pReqHdr->rc = vmmdevReqHandler_SetHypervisorInfo(pDevIns, pReqHdr);
2858 break;
2859
2860 case VMMDevReq_RegisterPatchMemory:
2861 pReqHdr->rc = vmmdevReqHandler_RegisterPatchMemory(pDevIns, pReqHdr);
2862 break;
2863
2864 case VMMDevReq_DeregisterPatchMemory:
2865 pReqHdr->rc = vmmdevReqHandler_DeregisterPatchMemory(pDevIns, pReqHdr);
2866 break;
2867
2868 case VMMDevReq_SetPowerStatus:
2869 {
2870 int rc = pReqHdr->rc = vmmdevReqHandler_SetPowerStatus(pDevIns, pThis, pReqHdr);
2871 if (rc != VINF_SUCCESS && RT_SUCCESS(rc))
2872 rcRet = rc;
2873 break;
2874 }
2875
2876 case VMMDevReq_GetDisplayChangeRequest:
2877 pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest(pThis, pReqHdr);
2878 break;
2879
2880 case VMMDevReq_GetDisplayChangeRequest2:
2881 pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequest2(pDevIns, pThis, pThisCC, pReqHdr);
2882 break;
2883
2884 case VMMDevReq_GetDisplayChangeRequestEx:
2885 pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequestEx(pDevIns, pThis, pThisCC, pReqHdr);
2886 break;
2887
2888 case VMMDevReq_GetDisplayChangeRequestMulti:
2889 pReqHdr->rc = vmmdevReqHandler_GetDisplayChangeRequestMulti(pThis, pReqHdr);
2890 break;
2891
2892 case VMMDevReq_VideoModeSupported:
2893 pReqHdr->rc = vmmdevReqHandler_VideoModeSupported(pThisCC, pReqHdr);
2894 break;
2895
2896 case VMMDevReq_VideoModeSupported2:
2897 pReqHdr->rc = vmmdevReqHandler_VideoModeSupported2(pThisCC, pReqHdr);
2898 break;
2899
2900 case VMMDevReq_GetHeightReduction:
2901 pReqHdr->rc = vmmdevReqHandler_GetHeightReduction(pThisCC, pReqHdr);
2902 break;
2903
2904 case VMMDevReq_AcknowledgeEvents:
2905 pReqHdr->rc = vmmdevReqHandler_AcknowledgeEvents(pDevIns, pThis, pThisCC, pReqHdr);
2906 break;
2907
2908 case VMMDevReq_CtlGuestFilterMask:
2909 pReqHdr->rc = vmmdevReqHandler_CtlGuestFilterMask(pDevIns, pThis, pThisCC, pReqHdr);
2910 break;
2911
2912#ifdef VBOX_WITH_HGCM
2913 case VMMDevReq_HGCMConnect:
2914 vmmdevReqHdrSetHgcmAsyncExecute(pDevIns, GCPhysReqHdr, *ppLock);
2915 pReqHdr->rc = vmmdevReqHandler_HGCMConnect(pDevIns, pThis, pThisCC, pReqHdr, GCPhysReqHdr);
2916 Assert(pReqHdr->rc == VINF_HGCM_ASYNC_EXECUTE || RT_FAILURE_NP(pReqHdr->rc));
2917 if (RT_SUCCESS(pReqHdr->rc))
2918 *pfPostOptimize |= VMMDEVREQDISP_POST_F_NO_WRITE_OUT;
2919 break;
2920
2921 case VMMDevReq_HGCMDisconnect:
2922 vmmdevReqHdrSetHgcmAsyncExecute(pDevIns, GCPhysReqHdr, *ppLock);
2923 pReqHdr->rc = vmmdevReqHandler_HGCMDisconnect(pDevIns, pThis, pThisCC, pReqHdr, GCPhysReqHdr);
2924 Assert(pReqHdr->rc == VINF_HGCM_ASYNC_EXECUTE || RT_FAILURE_NP(pReqHdr->rc));
2925 if (RT_SUCCESS(pReqHdr->rc))
2926 *pfPostOptimize |= VMMDEVREQDISP_POST_F_NO_WRITE_OUT;
2927 break;
2928
2929# ifdef VBOX_WITH_64_BITS_GUESTS
2930 case VMMDevReq_HGCMCall64:
2931# endif
2932 case VMMDevReq_HGCMCall32:
2933 vmmdevReqHdrSetHgcmAsyncExecute(pDevIns, GCPhysReqHdr, *ppLock);
2934 pReqHdr->rc = vmmdevReqHandler_HGCMCall(pDevIns, pThis, pThisCC, pReqHdr, GCPhysReqHdr, tsArrival, ppLock);
2935 Assert(pReqHdr->rc == VINF_HGCM_ASYNC_EXECUTE || RT_FAILURE_NP(pReqHdr->rc));
2936 if (RT_SUCCESS(pReqHdr->rc))
2937 *pfPostOptimize |= VMMDEVREQDISP_POST_F_NO_WRITE_OUT;
2938 break;
2939
2940 case VMMDevReq_HGCMCancel:
2941 pReqHdr->rc = vmmdevReqHandler_HGCMCancel(pThisCC, pReqHdr, GCPhysReqHdr);
2942 break;
2943
2944 case VMMDevReq_HGCMCancel2:
2945 pReqHdr->rc = vmmdevReqHandler_HGCMCancel2(pThisCC, pReqHdr);
2946 break;
2947#endif /* VBOX_WITH_HGCM */
2948
2949 case VMMDevReq_VideoAccelEnable:
2950 pReqHdr->rc = vmmdevReqHandler_VideoAccelEnable(pThis, pThisCC, pReqHdr);
2951 break;
2952
2953 case VMMDevReq_VideoAccelFlush:
2954 pReqHdr->rc = vmmdevReqHandler_VideoAccelFlush(pThisCC, pReqHdr);
2955 break;
2956
2957 case VMMDevReq_VideoSetVisibleRegion:
2958 pReqHdr->rc = vmmdevReqHandler_VideoSetVisibleRegion(pThisCC, pReqHdr);
2959 break;
2960
2961 case VMMDevReq_VideoUpdateMonitorPositions:
2962 pReqHdr->rc = vmmdevReqHandler_VideoUpdateMonitorPositions(pThisCC, pReqHdr);
2963 break;
2964
2965 case VMMDevReq_GetSeamlessChangeRequest:
2966 pReqHdr->rc = vmmdevReqHandler_GetSeamlessChangeRequest(pThis, pReqHdr);
2967 break;
2968
2969 case VMMDevReq_GetVRDPChangeRequest:
2970 pReqHdr->rc = vmmdevReqHandler_GetVRDPChangeRequest(pThis, pReqHdr);
2971 break;
2972
2973 case VMMDevReq_GetMemBalloonChangeRequest:
2974 pReqHdr->rc = vmmdevReqHandler_GetMemBalloonChangeRequest(pThis, pReqHdr);
2975 break;
2976
2977 case VMMDevReq_ChangeMemBalloon:
2978 pReqHdr->rc = vmmdevReqHandler_ChangeMemBalloon(pDevIns, pThis, pReqHdr);
2979 break;
2980
2981 case VMMDevReq_GetStatisticsChangeRequest:
2982 pReqHdr->rc = vmmdevReqHandler_GetStatisticsChangeRequest(pThis, pReqHdr);
2983 break;
2984
2985 case VMMDevReq_ReportGuestStats:
2986 pReqHdr->rc = vmmdevReqHandler_ReportGuestStats(pThisCC, pReqHdr);
2987 break;
2988
2989 case VMMDevReq_QueryCredentials:
2990 pReqHdr->rc = vmmdevReqHandler_QueryCredentials(pThis, pThisCC, pReqHdr);
2991 break;
2992
2993 case VMMDevReq_ReportCredentialsJudgement:
2994 pReqHdr->rc = vmmdevReqHandler_ReportCredentialsJudgement(pThisCC, pReqHdr);
2995 break;
2996
2997 case VMMDevReq_GetHostVersion:
2998 pReqHdr->rc = vmmdevReqHandler_GetHostVersion(pReqHdr);
2999 break;
3000
3001 case VMMDevReq_GetCpuHotPlugRequest:
3002 pReqHdr->rc = vmmdevReqHandler_GetCpuHotPlugRequest(pThis, pReqHdr);
3003 break;
3004
3005 case VMMDevReq_SetCpuHotPlugStatus:
3006 pReqHdr->rc = vmmdevReqHandler_SetCpuHotPlugStatus(pThis, pReqHdr);
3007 break;
3008
3009#ifdef VBOX_WITH_PAGE_SHARING
3010 case VMMDevReq_RegisterSharedModule:
3011 pReqHdr->rc = vmmdevReqHandler_RegisterSharedModule(pDevIns, pReqHdr);
3012 break;
3013
3014 case VMMDevReq_UnregisterSharedModule:
3015 pReqHdr->rc = vmmdevReqHandler_UnregisterSharedModule(pDevIns, pReqHdr);
3016 break;
3017
3018 case VMMDevReq_CheckSharedModules:
3019 pReqHdr->rc = vmmdevReqHandler_CheckSharedModules(pDevIns, pReqHdr);
3020 break;
3021
3022 case VMMDevReq_GetPageSharingStatus:
3023 pReqHdr->rc = vmmdevReqHandler_GetPageSharingStatus(pThisCC, pReqHdr);
3024 break;
3025
3026 case VMMDevReq_DebugIsPageShared:
3027 pReqHdr->rc = vmmdevReqHandler_DebugIsPageShared(pDevIns, pReqHdr);
3028 break;
3029
3030#endif /* VBOX_WITH_PAGE_SHARING */
3031
3032#ifdef DEBUG
3033 case VMMDevReq_LogString:
3034 pReqHdr->rc = vmmdevReqHandler_LogString(pReqHdr);
3035 break;
3036#endif
3037
3038 case VMMDevReq_GetSessionId:
3039 pReqHdr->rc = vmmdevReqHandler_GetSessionId(pThis, pReqHdr);
3040 break;
3041
3042 /*
3043 * Guest wants to give up a timeslice.
3044 * Note! This was only ever used by experimental GAs!
3045 */
3046 /** @todo maybe we could just remove this? */
3047 case VMMDevReq_Idle:
3048 {
3049 /* just return to EMT telling it that we want to halt */
3050 rcRet = VINF_EM_HALT;
3051 break;
3052 }
3053
3054 case VMMDevReq_GuestHeartbeat:
3055 pReqHdr->rc = vmmDevReqHandler_GuestHeartbeat(pDevIns, pThis);
3056 break;
3057
3058 case VMMDevReq_HeartbeatConfigure:
3059 pReqHdr->rc = vmmDevReqHandler_HeartbeatConfigure(pDevIns, pThis, pReqHdr);
3060 break;
3061
3062 case VMMDevReq_NtBugCheck:
3063 pReqHdr->rc = vmmDevReqHandler_NtBugCheck(pDevIns, pReqHdr);
3064 break;
3065
3066 default:
3067 {
3068 pReqHdr->rc = VERR_NOT_IMPLEMENTED;
3069 Log(("VMMDev unknown request type %d\n", pReqHdr->requestType));
3070 break;
3071 }
3072 }
3073 return rcRet;
3074}
3075
3076
3077/**
3078 * @callback_method_impl{FNIOMIOPORTNEWOUT,
3079 * Port I/O write andler for the generic request interface.}
3080 */
3081static DECLCALLBACK(VBOXSTRICTRC)
3082vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3083{
3084 uint64_t tsArrival;
3085 STAM_GET_TS(tsArrival);
3086
3087 RT_NOREF(offPort, cb, pvUser);
3088
3089 /*
3090 * The caller has passed the guest context physical address of the request
3091 * structure. We'll copy all of it into a heap buffer eventually, but we
3092 * will have to start off with the header.
3093 */
3094 VMMDevRequestHeader requestHeader;
3095 RT_ZERO(requestHeader);
3096 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
3097
3098 /* The structure size must be greater or equal to the header size. */
3099 if (requestHeader.size < sizeof(VMMDevRequestHeader))
3100 {
3101 Log(("VMMDev request header size too small! size = %d\n", requestHeader.size));
3102 return VINF_SUCCESS;
3103 }
3104
3105 /* Check the version of the header structure. */
3106 if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
3107 {
3108 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
3109 return VINF_SUCCESS;
3110 }
3111
3112 Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
3113
3114 VBOXSTRICTRC rcRet = VINF_SUCCESS;
3115 /* Check that is doesn't exceed the max packet size. */
3116 if (requestHeader.size <= VMMDEV_MAX_VMMDEVREQ_SIZE)
3117 {
3118 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3119 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
3120
3121 /*
3122 * We require the GAs to report it's information before we let it have
3123 * access to all the functions. The VMMDevReq_ReportGuestInfo request
3124 * is the one which unlocks the access. Newer additions will first
3125 * issue VMMDevReq_ReportGuestInfo2, older ones doesn't know this one.
3126 * Two exceptions: VMMDevReq_GetHostVersion and VMMDevReq_WriteCoreDump.
3127 */
3128 if ( pThis->fu32AdditionsOk
3129 || requestHeader.requestType == VMMDevReq_ReportGuestInfo2
3130 || requestHeader.requestType == VMMDevReq_ReportGuestInfo
3131 || requestHeader.requestType == VMMDevReq_WriteCoreDump
3132 || requestHeader.requestType == VMMDevReq_GetHostVersion
3133 )
3134 {
3135 /*
3136 * The request looks fine. Copy it into a buffer.
3137 *
3138 * The buffer is only used while on this thread, and this thread is one
3139 * of the EMTs, so we keep a 4KB buffer for each EMT around to avoid
3140 * wasting time with the heap. Larger allocations goes to the heap, though.
3141 */
3142 VMCPUID iCpu = PDMDevHlpGetCurrentCpuId(pDevIns);
3143 VMMDevRequestHeader *pRequestHeaderFree = NULL;
3144 VMMDevRequestHeader *pRequestHeader = NULL;
3145 if ( requestHeader.size <= _4K
3146 && iCpu < RT_ELEMENTS(pThisCC->apReqBufs))
3147 {
3148 pRequestHeader = pThisCC->apReqBufs[iCpu];
3149 if (pRequestHeader)
3150 { /* likely */ }
3151 else
3152 pThisCC->apReqBufs[iCpu] = pRequestHeader = (VMMDevRequestHeader *)RTMemPageAlloc(_4K);
3153 }
3154 else
3155 {
3156 Assert(iCpu != NIL_VMCPUID);
3157 STAM_REL_COUNTER_INC(&pThisCC->StatReqBufAllocs);
3158 pRequestHeaderFree = pRequestHeader = (VMMDevRequestHeader *)RTMemAlloc(RT_MAX(requestHeader.size, 512));
3159 }
3160 if (pRequestHeader)
3161 {
3162 memcpy(pRequestHeader, &requestHeader, sizeof(VMMDevRequestHeader));
3163
3164 /* Try lock the request if it's a HGCM call and not crossing a page boundrary.
3165 Saves on PGM interaction. */
3166 VMMDEVREQLOCK Lock = { NULL, { 0, NULL } };
3167 PVMMDEVREQLOCK pLock = NULL;
3168 size_t cbLeft = requestHeader.size - sizeof(VMMDevRequestHeader);
3169 if (cbLeft)
3170 {
3171 if ( ( requestHeader.requestType == VMMDevReq_HGCMCall32
3172 || requestHeader.requestType == VMMDevReq_HGCMCall64)
3173 && ((u32 + requestHeader.size) >> X86_PAGE_SHIFT) == (u32 >> X86_PAGE_SHIFT)
3174 && RT_SUCCESS(PDMDevHlpPhysGCPhys2CCPtr(pDevIns, u32, 0 /*fFlags*/, &Lock.pvReq, &Lock.Lock)) )
3175 {
3176 memcpy((uint8_t *)pRequestHeader + sizeof(VMMDevRequestHeader),
3177 (uint8_t *)Lock.pvReq + sizeof(VMMDevRequestHeader), cbLeft);
3178 pLock = &Lock;
3179 }
3180 else
3181 PDMDevHlpPhysRead(pDevIns,
3182 (RTGCPHYS)u32 + sizeof(VMMDevRequestHeader),
3183 (uint8_t *)pRequestHeader + sizeof(VMMDevRequestHeader),
3184 cbLeft);
3185 }
3186
3187 /*
3188 * Feed buffered request thru the dispatcher.
3189 */
3190 uint32_t fPostOptimize = 0;
3191 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3192 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
3193
3194 rcRet = vmmdevReqDispatcher(pDevIns, pThis, pThisCC, pRequestHeader, u32, tsArrival, &fPostOptimize, &pLock);
3195
3196 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3197
3198 /*
3199 * Write the result back to guest memory (unless it is a locked HGCM call).
3200 */
3201 if (!(fPostOptimize & VMMDEVREQDISP_POST_F_NO_WRITE_OUT))
3202 {
3203 if (pLock)
3204 memcpy(pLock->pvReq, pRequestHeader, pRequestHeader->size);
3205 else
3206 PDMDevHlpPhysWrite(pDevIns, u32, pRequestHeader, pRequestHeader->size);
3207 }
3208
3209 if (!pRequestHeaderFree)
3210 { /* likely */ }
3211 else
3212 RTMemFreeZ(pRequestHeaderFree, RT_MAX(requestHeader.size, 512));
3213 return rcRet;
3214 }
3215
3216 Log(("VMMDev: RTMemAlloc failed!\n"));
3217 requestHeader.rc = VERR_NO_MEMORY;
3218 }
3219 else
3220 {
3221 LogRelMax(10, ("VMMDev: Guest has not yet reported to us -- refusing operation of request #%d\n",
3222 requestHeader.requestType));
3223 requestHeader.rc = VERR_NOT_SUPPORTED;
3224 }
3225 }
3226 else
3227 {
3228 LogRelMax(50, ("VMMDev: Request packet too big (%x), refusing operation\n", requestHeader.size));
3229 requestHeader.rc = VERR_NOT_SUPPORTED;
3230 }
3231
3232 /*
3233 * Write the result back to guest memory.
3234 */
3235 PDMDevHlpPhysWrite(pDevIns, u32, &requestHeader, sizeof(requestHeader));
3236
3237 return rcRet;
3238}
3239
3240#endif /* IN_RING3 */
3241
3242
3243/**
3244 * @callback_method_impl{FNIOMIOPORTOUT, Port I/O write handler for requests
3245 * that can be handled w/o going to ring-3.}
3246 */
3247static DECLCALLBACK(VBOXSTRICTRC)
3248vmmdevFastRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3249{
3250#ifndef IN_RING3
3251# if 0 /* This functionality is offered through reading the port (vmmdevFastRequestIrqAck). Leaving it here for later. */
3252 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3253 RT_NOREF(pvUser, Port, cb);
3254
3255 /*
3256 * We only process a limited set of requests here, reflecting the rest down
3257 * to ring-3. So, try read the whole request into a stack buffer and check
3258 * if we can handle it.
3259 */
3260 union
3261 {
3262 VMMDevRequestHeader Hdr;
3263 VMMDevEvents Ack;
3264 } uReq;
3265 RT_ZERO(uReq);
3266
3267 VBOXSTRICTRC rcStrict;
3268 if (pThis->fu32AdditionsOk)
3269 {
3270 /* Read it into memory. */
3271 uint32_t cbToRead = sizeof(uReq); /* (Adjust to stay within a page if we support more than ack requests.) */
3272 rcStrict = PDMDevHlpPhysRead(pDevIns, u32, &uReq, cbToRead);
3273 if (rcStrict == VINF_SUCCESS)
3274 {
3275 /*
3276 * Validate the request and check that we want to handle it here.
3277 */
3278 if ( uReq.Hdr.size >= sizeof(uReq.Hdr)
3279 && uReq.Hdr.version == VMMDEV_REQUEST_HEADER_VERSION
3280 && ( uReq.Hdr.requestType == VMMDevReq_AcknowledgeEvents
3281 && uReq.Hdr.size == sizeof(uReq.Ack)
3282 && cbToRead == sizeof(uReq.Ack)
3283 && pThisCC->CTX_SUFF(pVMMDevRAM) != NULL)
3284 )
3285 {
3286 RT_UNTRUSTED_VALIDATED_FENCE();
3287
3288 /*
3289 * Try grab the critical section.
3290 */
3291 int rc2 = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
3292 if (rc2 == VINF_SUCCESS)
3293 {
3294 /*
3295 * Handle the request and write back the result to the guest.
3296 */
3297 uReq.Hdr.rc = vmmdevReqHandler_AcknowledgeEvents(pThis, &uReq.Hdr);
3298
3299 rcStrict = PDMDevHlpPhysWrite(pDevIns, u32, &uReq, uReq.Hdr.size);
3300 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3301 if (rcStrict == VINF_SUCCESS)
3302 { /* likely */ }
3303 else
3304 Log(("vmmdevFastRequestHandler: PDMDevHlpPhysWrite(%#RX32+rc,4) -> %Rrc (%RTbool)\n",
3305 u32, VBOXSTRICTRC_VAL(rcStrict), PGM_PHYS_RW_IS_SUCCESS(rcStrict) ));
3306 }
3307 else
3308 {
3309 Log(("vmmdevFastRequestHandler: PDMDevHlpPDMCritSectEnter -> %Rrc\n", rc2));
3310 rcStrict = rc2;
3311 }
3312 }
3313 else
3314 {
3315 Log(("vmmdevFastRequestHandler: size=%#x version=%#x requestType=%d (pVMMDevRAM=%p) -> R3\n",
3316 uReq.Hdr.size, uReq.Hdr.version, uReq.Hdr.requestType, pThisCC->CTX_SUFF(pVMMDevRAM) ));
3317 rcStrict = VINF_IOM_R3_IOPORT_WRITE;
3318 }
3319 }
3320 else
3321 Log(("vmmdevFastRequestHandler: PDMDevHlpPhysRead(%#RX32,%#RX32) -> %Rrc\n", u32, cbToRead, VBOXSTRICTRC_VAL(rcStrict)));
3322 }
3323 else
3324 {
3325 Log(("vmmdevFastRequestHandler: additions nok-okay\n"));
3326 rcStrict = VINF_IOM_R3_IOPORT_WRITE;
3327 }
3328
3329 return VBOXSTRICTRC_VAL(rcStrict);
3330# else
3331 RT_NOREF(pDevIns, pvUser, offPort, u32, cb);
3332 return VINF_IOM_R3_IOPORT_WRITE;
3333# endif
3334
3335#else /* IN_RING3 */
3336 return vmmdevRequestHandler(pDevIns, pvUser, offPort, u32, cb);
3337#endif /* IN_RING3 */
3338}
3339
3340
3341/**
3342 * @callback_method_impl{FNIOMIOPORTNEWIN,
3343 * Port I/O read handler for IRQ acknowledging and getting pending events (same
3344 * as VMMDevReq_AcknowledgeEvents - just faster).}
3345 */
3346static DECLCALLBACK(VBOXSTRICTRC)
3347vmmdevFastRequestIrqAck(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
3348{
3349 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3350 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
3351 Assert(PDMDEVINS_2_DATA(pDevIns, PVMMDEV) == pThis);
3352 RT_NOREF(pvUser, offPort);
3353
3354 /* Only 32-bit accesses. */
3355 ASSERT_GUEST_MSG_RETURN(cb == sizeof(uint32_t), ("cb=%d\n", cb), VERR_IOM_IOPORT_UNUSED);
3356
3357 /* The VMMDev memory mapping might've failed, go to ring-3 in that case. */
3358 VBOXSTRICTRC rcStrict;
3359#ifndef IN_RING3
3360 if (pThisCC->CTX_SUFF(pVMMDevRAM) != NULL)
3361#endif
3362 {
3363 /* Enter critical section and check that the additions has been properly
3364 initialized and that we're not in legacy v1.3 device mode. */
3365 rcStrict = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
3366 if (rcStrict == VINF_SUCCESS)
3367 {
3368 if ( pThis->fu32AdditionsOk
3369 && !VMMDEV_INTERFACE_VERSION_IS_1_03(pThis))
3370 {
3371 /*
3372 * Do the job.
3373 *
3374 * Note! This code is duplicated in vmmdevReqHandler_AcknowledgeEvents.
3375 */
3376 STAM_REL_COUNTER_INC(&pThis->CTX_SUFF_Z(StatFastIrqAck));
3377
3378 if (pThis->fNewGuestFilterMaskValid)
3379 {
3380 pThis->fNewGuestFilterMaskValid = false;
3381 pThis->fGuestFilterMask = pThis->fNewGuestFilterMask;
3382 }
3383
3384 *pu32 = pThis->fHostEventFlags & pThis->fGuestFilterMask;
3385
3386 pThis->fHostEventFlags &= ~pThis->fGuestFilterMask;
3387 pThisCC->CTX_SUFF(pVMMDevRAM)->V.V1_04.fHaveEvents = false;
3388
3389 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 0);
3390 }
3391 else
3392 {
3393 Log(("vmmdevFastRequestIrqAck: fu32AdditionsOk=%d interfaceVersion=%#x\n", pThis->fu32AdditionsOk,
3394 pThis->guestInfo.interfaceVersion));
3395 *pu32 = UINT32_MAX;
3396 }
3397
3398 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3399 }
3400 }
3401#ifndef IN_RING3
3402 else
3403 rcStrict = VINF_IOM_R3_IOPORT_READ;
3404#endif
3405 return rcStrict;
3406}
3407
3408
3409
3410#ifdef IN_RING3
3411
3412/* -=-=-=-=-=- PCI Device -=-=-=-=-=- */
3413
3414/**
3415 * @callback_method_impl{FNPCIIOREGIONMAP,I/O Port Region}
3416 */
3417static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
3418 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
3419{
3420 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3421 LogFlow(("vmmdevIOPortRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
3422 RT_NOREF(pPciDev, iRegion, cb, enmType);
3423
3424 Assert(pPciDev == pDevIns->apPciDevs[0]);
3425 Assert(enmType == PCI_ADDRESS_SPACE_IO);
3426 Assert(iRegion == 0);
3427
3428 int rc;
3429 if (GCPhysAddress != NIL_RTGCPHYS)
3430 {
3431 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#RGp\n", GCPhysAddress));
3432
3433 rc = PDMDevHlpIoPortMap(pDevIns, pThis->hIoPortReq, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST);
3434 AssertLogRelRCReturn(rc, rc);
3435
3436 rc = PDMDevHlpIoPortMap(pDevIns, pThis->hIoPortFast, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST_FAST);
3437 AssertLogRelRCReturn(rc, rc);
3438 }
3439 else
3440 {
3441 rc = PDMDevHlpIoPortUnmap(pDevIns, pThis->hIoPortReq);
3442 AssertLogRelRCReturn(rc, rc);
3443
3444 rc = PDMDevHlpIoPortUnmap(pDevIns, pThis->hIoPortFast);
3445 AssertLogRelRCReturn(rc, rc);
3446 }
3447 return rc;
3448}
3449
3450
3451/**
3452 * @callback_method_impl{FNPCIIOREGIONMAP,VMMDev heap (MMIO2)}
3453 */
3454static DECLCALLBACK(int) vmmdevMmio2HeapRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
3455 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
3456{
3457 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
3458 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
3459 RT_NOREF(cb, pPciDev);
3460
3461 Assert(pPciDev == pDevIns->apPciDevs[0]);
3462 AssertReturn(iRegion == 2, VERR_INTERNAL_ERROR_2);
3463 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR_3);
3464 Assert(pThisCC->pVMMDevHeapR3 != NULL);
3465
3466 int rc;
3467 if (GCPhysAddress != NIL_RTGCPHYS)
3468 {
3469 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, GCPhysAddress, pThisCC->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
3470 AssertRC(rc);
3471 }
3472 else
3473 {
3474 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThisCC->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
3475 AssertRCStmt(rc, rc = VINF_SUCCESS);
3476 }
3477
3478 return rc;
3479}
3480
3481
3482/* -=-=-=-=-=- Backdoor Logging and Time Sync. -=-=-=-=-=- */
3483
3484/**
3485 * @callback_method_impl{FNIOMIOPORTNEWOUT, Backdoor Logging.}
3486 */
3487static DECLCALLBACK(VBOXSTRICTRC)
3488vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3489{
3490 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3491 RT_NOREF(pvUser, offPort);
3492 Assert(offPort == 0);
3493
3494 if (!pThis->fBackdoorLogDisabled && cb == 1)
3495 {
3496
3497 /* The raw version. */
3498 switch (u32)
3499 {
3500 case '\r': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
3501 case '\n': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
3502 case '\t': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
3503 default: LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: %c (%02x)\n", u32, u32)); break;
3504 }
3505
3506 /* The readable, buffered version. */
3507 uint32_t offMsg = RT_MIN(pThis->offMsg, sizeof(pThis->szMsg) - 1);
3508 if (u32 == '\n' || u32 == '\r')
3509 {
3510 pThis->szMsg[offMsg] = '\0';
3511 if (offMsg)
3512 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %.*s\n", offMsg, pThis->szMsg));
3513 pThis->offMsg = 0;
3514 }
3515 else
3516 {
3517 if (offMsg >= sizeof(pThis->szMsg) - 1)
3518 {
3519 pThis->szMsg[sizeof(pThis->szMsg) - 1] = '\0';
3520 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR,
3521 ("VMMDev: Guest Log: %.*s\n", sizeof(pThis->szMsg) - 1, pThis->szMsg));
3522 offMsg = 0;
3523 }
3524 pThis->szMsg[offMsg++] = (char )u32;
3525 pThis->szMsg[offMsg] = '\0';
3526 pThis->offMsg = offMsg;
3527 }
3528 }
3529 return VINF_SUCCESS;
3530}
3531
3532#ifdef VMMDEV_WITH_ALT_TIMESYNC
3533
3534/**
3535 * @callback_method_impl{FNIOMIOPORTNEWOUT, Alternative time synchronization.}
3536 */
3537static DECLCALLBACK(VBOXSTRICTRC)
3538vmmdevAltTimeSyncWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3539{
3540 RT_NOREF(pvUser, offPort);
3541 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3542 if (cb == 4)
3543 {
3544 /* Selects high (0) or low (1) DWORD. The high has to be read first. */
3545 switch (u32)
3546 {
3547 case 0:
3548 pThis->fTimesyncBackdoorLo = false;
3549 break;
3550 case 1:
3551 pThis->fTimesyncBackdoorLo = true;
3552 break;
3553 default:
3554 Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
3555 break;
3556 }
3557 }
3558 else
3559 Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
3560 return VINF_SUCCESS;
3561}
3562
3563/**
3564 * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
3565 */
3566static DECLCALLBACK(VBOXSTRICTRC)
3567vmmdevAltTimeSyncRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
3568{
3569 RT_NOREF(pvUser, offPort);
3570 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3571 VBOXSTRICTRC rc;
3572 if (cb == 4)
3573 {
3574 if (pThis->fTimesyncBackdoorLo)
3575 *pu32 = (uint32_t)pThis->msLatchedHostTime;
3576 else
3577 {
3578 /* Reading the high dword gets and saves the current time. */
3579 RTTIMESPEC Now;
3580 pThis->msLatchedHostTime = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &Now));
3581 *pu32 = (uint32_t)(pThis->msLatchedHostTime >> 32);
3582 }
3583 rc = VINF_SUCCESS;
3584 }
3585 else
3586 {
3587 Log(("vmmdevAltTimeSyncRead: Invalid access cb=%#x\n", cb));
3588 rc = VERR_IOM_IOPORT_UNUSED;
3589 }
3590 return rc;
3591}
3592
3593#endif /* VMMDEV_WITH_ALT_TIMESYNC */
3594
3595
3596/* -=-=-=-=-=- IBase -=-=-=-=-=- */
3597
3598/**
3599 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3600 */
3601static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3602{
3603 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IBase);
3604
3605 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
3606 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThisCC->IPort);
3607#ifdef VBOX_WITH_HGCM
3608 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMPORT, &pThisCC->IHGCMPort);
3609#endif
3610 /* Currently only for shared folders. */
3611 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->SharedFolders.ILeds);
3612 return NULL;
3613}
3614
3615
3616/* -=-=-=-=-=- ILeds -=-=-=-=-=- */
3617
3618/**
3619 * Gets the pointer to the status LED of a unit.
3620 *
3621 * @returns VBox status code.
3622 * @param pInterface Pointer to the interface structure containing the called function pointer.
3623 * @param iLUN The unit which status LED we desire.
3624 * @param ppLed Where to store the LED pointer.
3625 */
3626static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
3627{
3628 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, SharedFolders.ILeds);
3629 if (iLUN == 0) /* LUN 0 is shared folders */
3630 {
3631 *ppLed = &pThisCC->SharedFolders.Led;
3632 return VINF_SUCCESS;
3633 }
3634 return VERR_PDM_LUN_NOT_FOUND;
3635}
3636
3637
3638/* -=-=-=-=-=- PDMIVMMDEVPORT (VMMDEV::IPort) -=-=-=-=-=- */
3639
3640/**
3641 * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryAbsoluteMouse}
3642 */
3643static DECLCALLBACK(int) vmmdevIPort_QueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)
3644{
3645 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3646 PVMMDEV pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVMMDEV);
3647
3648 /** @todo at the first sign of trouble in this area, just enter the critsect.
3649 * As indicated by the comment below, the atomic reads serves no real purpose
3650 * here since we can assume cache coherency protocoles and int32_t alignment
3651 * rules making sure we won't see a halfwritten value. */
3652 if (pxAbs)
3653 *pxAbs = ASMAtomicReadS32(&pThis->xMouseAbs); /* why the atomic read? */
3654 if (pyAbs)
3655 *pyAbs = ASMAtomicReadS32(&pThis->yMouseAbs);
3656
3657 return VINF_SUCCESS;
3658}
3659
3660/**
3661 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetAbsoluteMouse}
3662 */
3663static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs,
3664 int32_t dz, int32_t dw, uint32_t fButtons)
3665{
3666 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3667 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3668 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3669 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3670 AssertRCReturn(rcLock, rcLock);
3671
3672 if ( pThis->xMouseAbs != xAbs
3673 || pThis->yMouseAbs != yAbs
3674 || dz
3675 || dw
3676 || pThis->fMouseButtons != fButtons)
3677 {
3678 Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d, z = %d, w = %d, fButtons = 0x%x\n",
3679 xAbs, yAbs, dz, dw, fButtons));
3680
3681 pThis->xMouseAbs = xAbs;
3682 pThis->yMouseAbs = yAbs;
3683 pThis->dzMouse = dz;
3684 pThis->dwMouse = dw;
3685 pThis->fMouseButtons = fButtons;
3686
3687 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
3688 }
3689
3690 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3691 return VINF_SUCCESS;
3692}
3693
3694/**
3695 * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryMouseCapabilities}
3696 */
3697static DECLCALLBACK(int) vmmdevIPort_QueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)
3698{
3699 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3700 PVMMDEV pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVMMDEV);
3701 AssertPtrReturn(pfCapabilities, VERR_INVALID_PARAMETER);
3702
3703 *pfCapabilities = pThis->fMouseCapabilities;
3704 return VINF_SUCCESS;
3705}
3706
3707/**
3708 * @interface_method_impl{PDMIVMMDEVPORT,pfnUpdateMouseCapabilities}
3709 */
3710static DECLCALLBACK(int)
3711vmmdevIPort_UpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)
3712{
3713 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3714 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3715 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3716 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3717 AssertRCReturn(rcLock, rcLock);
3718
3719 uint32_t fOldCaps = pThis->fMouseCapabilities;
3720 pThis->fMouseCapabilities &= ~(fCapsRemoved & VMMDEV_MOUSE_HOST_MASK);
3721 pThis->fMouseCapabilities |= (fCapsAdded & VMMDEV_MOUSE_HOST_MASK)
3722 | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR
3723 | VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL;
3724 bool fNotify = fOldCaps != pThis->fMouseCapabilities;
3725
3726 LogRelFlow(("VMMDev: vmmdevIPort_UpdateMouseCapabilities: fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify=%RTbool\n", fCapsAdded,
3727 fCapsRemoved, fNotify));
3728
3729 if (fNotify)
3730 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
3731
3732 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3733 return VINF_SUCCESS;
3734}
3735
3736static bool vmmdevIsMonitorDefEqual(VMMDevDisplayDef const *pNew, VMMDevDisplayDef const *pOld)
3737{
3738 bool fEqual = pNew->idDisplay == pOld->idDisplay;
3739
3740 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN) /* No change. */
3741 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN) /* Old value exists and */
3742 && pNew->xOrigin == pOld->xOrigin /* the old is equal to the new. */
3743 && pNew->yOrigin == pOld->yOrigin));
3744
3745 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_CX)
3746 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_CX)
3747 && pNew->cx == pOld->cx));
3748
3749 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_CY)
3750 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_CY)
3751 && pNew->cy == pOld->cy));
3752
3753 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_BPP)
3754 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_BPP)
3755 && pNew->cBitsPerPixel == pOld->cBitsPerPixel));
3756
3757 fEqual = fEqual && ( RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_DISABLED)
3758 == RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_DISABLED));
3759
3760 fEqual = fEqual && ( RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_PRIMARY)
3761 == RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_PRIMARY));
3762
3763 return fEqual;
3764}
3765
3766/**
3767 * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestDisplayChange}
3768 */
3769static DECLCALLBACK(int)
3770vmmdevIPort_RequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t cDisplays, VMMDevDisplayDef const *paDisplays, bool fForce, bool fMayNotify)
3771{
3772 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3773 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3774 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3775 int rc = VINF_SUCCESS;
3776 bool fNotifyGuest = false;
3777 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3778 AssertRCReturn(rcLock, rcLock);
3779
3780 uint32_t i;
3781 for (i = 0; i < cDisplays; ++i)
3782 {
3783 VMMDevDisplayDef const *p = &paDisplays[i];
3784
3785 /* Either one display definition is provided or the display id must be equal to the array index. */
3786 AssertBreakStmt(cDisplays == 1 || p->idDisplay == i, rc = VERR_INVALID_PARAMETER);
3787 AssertBreakStmt(p->idDisplay < RT_ELEMENTS(pThis->displayChangeData.aRequests), rc = VERR_INVALID_PARAMETER);
3788
3789 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[p->idDisplay];
3790
3791 VMMDevDisplayDef const *pLastRead = &pRequest->lastReadDisplayChangeRequest;
3792
3793 /* Verify that the new resolution is different and that guest does not yet know about it. */
3794 bool const fDifferentResolution = fForce || !vmmdevIsMonitorDefEqual(p, pLastRead);
3795
3796 LogFunc(("same=%d. New: %dx%d, cBits=%d, id=%d. Old: %dx%d, cBits=%d, id=%d. @%d,%d, Enabled=%d, ChangeOrigin=%d\n",
3797 !fDifferentResolution, p->cx, p->cy, p->cBitsPerPixel, p->idDisplay,
3798 pLastRead->cx, pLastRead->cy, pLastRead->cBitsPerPixel, pLastRead->idDisplay,
3799 p->xOrigin, p->yOrigin,
3800 !RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_DISABLED),
3801 RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN)));
3802
3803 /* We could validate the information here but hey, the guest can do that as well! */
3804 pRequest->displayChangeRequest = *p;
3805 pRequest->fPending = fDifferentResolution && fMayNotify;
3806
3807 fNotifyGuest = fNotifyGuest || fDifferentResolution;
3808 }
3809
3810 if (RT_SUCCESS(rc) && fMayNotify)
3811 {
3812 if (fNotifyGuest)
3813 {
3814 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); ++i)
3815 {
3816 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
3817 if (pRequest->fPending)
3818 {
3819 VMMDevDisplayDef const *p = &pRequest->displayChangeRequest;
3820 LogRel(("VMMDev: SetVideoModeHint: Got a video mode hint (%dx%dx%d)@(%dx%d),(%d;%d) at %d\n",
3821 p->cx, p->cy, p->cBitsPerPixel, p->xOrigin, p->yOrigin,
3822 !RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_DISABLED),
3823 RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN), i));
3824 }
3825 }
3826
3827 /* IRQ so the guest knows what's going on */
3828 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
3829 }
3830 }
3831
3832 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3833 return rc;
3834}
3835
3836/**
3837 * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestSeamlessChange}
3838 */
3839static DECLCALLBACK(int) vmmdevIPort_RequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
3840{
3841 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3842 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3843 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3844 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3845 AssertRCReturn(rcLock, rcLock);
3846
3847 /* Verify that the new resolution is different and that guest does not yet know about it. */
3848 bool fSameMode = (pThis->fLastSeamlessEnabled == fEnabled);
3849
3850 Log(("vmmdevIPort_RequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
3851
3852 if (!fSameMode)
3853 {
3854 /* we could validate the information here but hey, the guest can do that as well! */
3855 pThis->fSeamlessEnabled = fEnabled;
3856
3857 /* IRQ so the guest knows what's going on */
3858 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
3859 }
3860
3861 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3862 return VINF_SUCCESS;
3863}
3864
3865/**
3866 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetMemoryBalloon}
3867 */
3868static DECLCALLBACK(int) vmmdevIPort_SetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)
3869{
3870 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3871 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3872 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3873 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3874 AssertRCReturn(rcLock, rcLock);
3875
3876 /* Verify that the new resolution is different and that guest does not yet know about it. */
3877 Log(("vmmdevIPort_SetMemoryBalloon: old=%u new=%u\n", pThis->cMbMemoryBalloonLast, cMbBalloon));
3878 if (pThis->cMbMemoryBalloonLast != cMbBalloon)
3879 {
3880 /* we could validate the information here but hey, the guest can do that as well! */
3881 pThis->cMbMemoryBalloon = cMbBalloon;
3882
3883 /* IRQ so the guest knows what's going on */
3884 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
3885 }
3886
3887 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3888 return VINF_SUCCESS;
3889}
3890
3891/**
3892 * @interface_method_impl{PDMIVMMDEVPORT,pfnVRDPChange}
3893 */
3894static DECLCALLBACK(int) vmmdevIPort_VRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)
3895{
3896 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3897 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3898 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3899 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3900 AssertRCReturn(rcLock, rcLock);
3901
3902 bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
3903
3904 Log(("vmmdevIPort_VRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
3905
3906 if (!fSame)
3907 {
3908 pThis->fVRDPEnabled = fVRDPEnabled;
3909 pThis->uVRDPExperienceLevel = uVRDPExperienceLevel;
3910
3911 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_VRDP);
3912 }
3913
3914 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3915 return VINF_SUCCESS;
3916}
3917
3918/**
3919 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetStatisticsInterval}
3920 */
3921static DECLCALLBACK(int) vmmdevIPort_SetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)
3922{
3923 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3924 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3925 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3926 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3927 AssertRCReturn(rcLock, rcLock);
3928
3929 /* Verify that the new resolution is different and that guest does not yet know about it. */
3930 bool fSame = (pThis->cSecsLastStatInterval == cSecsStatInterval);
3931
3932 Log(("vmmdevIPort_SetStatisticsInterval: old=%d. new=%d\n", pThis->cSecsLastStatInterval, cSecsStatInterval));
3933
3934 if (!fSame)
3935 {
3936 /* we could validate the information here but hey, the guest can do that as well! */
3937 pThis->cSecsStatInterval = cSecsStatInterval;
3938
3939 /* IRQ so the guest knows what's going on */
3940 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
3941 }
3942
3943 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3944 return VINF_SUCCESS;
3945}
3946
3947/**
3948 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetCredentials}
3949 */
3950static DECLCALLBACK(int) vmmdevIPort_SetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
3951 const char *pszPassword, const char *pszDomain, uint32_t fFlags)
3952{
3953 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3954 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3955 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3956
3957 AssertReturn(fFlags & (VMMDEV_SETCREDENTIALS_GUESTLOGON | VMMDEV_SETCREDENTIALS_JUDGE), VERR_INVALID_PARAMETER);
3958 size_t const cchUsername = strlen(pszUsername);
3959 AssertReturn(cchUsername < VMMDEV_CREDENTIALS_SZ_SIZE, VERR_BUFFER_OVERFLOW);
3960 size_t const cchPassword = strlen(pszPassword);
3961 AssertReturn(cchPassword < VMMDEV_CREDENTIALS_SZ_SIZE, VERR_BUFFER_OVERFLOW);
3962 size_t const cchDomain = strlen(pszDomain);
3963 AssertReturn(cchDomain < VMMDEV_CREDENTIALS_SZ_SIZE, VERR_BUFFER_OVERFLOW);
3964
3965 VMMDEVCREDS *pCredentials = pThisCC->pCredentials;
3966 AssertPtrReturn(pCredentials, VERR_NOT_SUPPORTED);
3967
3968 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3969 AssertRCReturn(rcLock, rcLock);
3970
3971 /*
3972 * Logon mode
3973 */
3974 if (fFlags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
3975 {
3976 /* memorize the data */
3977 memcpy(pCredentials->Logon.szUserName, pszUsername, cchUsername);
3978 pThisCC->pCredentials->Logon.szUserName[cchUsername] = '\0';
3979 memcpy(pCredentials->Logon.szPassword, pszPassword, cchPassword);
3980 pCredentials->Logon.szPassword[cchPassword] = '\0';
3981 memcpy(pCredentials->Logon.szDomain, pszDomain, cchDomain);
3982 pCredentials->Logon.szDomain[cchDomain] = '\0';
3983 pCredentials->Logon.fAllowInteractiveLogon = !(fFlags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
3984 }
3985 /*
3986 * Credentials verification mode?
3987 */
3988 else
3989 {
3990 /* memorize the data */
3991 memcpy(pCredentials->Judge.szUserName, pszUsername, cchUsername);
3992 pCredentials->Judge.szUserName[cchUsername] = '\0';
3993 memcpy(pCredentials->Judge.szPassword, pszPassword, cchPassword);
3994 pCredentials->Judge.szPassword[cchPassword] = '\0';
3995 memcpy(pCredentials->Judge.szDomain, pszDomain, cchDomain);
3996 pCredentials->Judge.szDomain[cchDomain] = '\0';
3997
3998 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_JUDGE_CREDENTIALS);
3999 }
4000
4001 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4002 return VINF_SUCCESS;
4003}
4004
4005/**
4006 * @interface_method_impl{PDMIVMMDEVPORT,pfnVBVAChange}
4007 *
4008 * Notification from the Display. Especially useful when acceleration is
4009 * disabled after a video mode change.
4010 */
4011static DECLCALLBACK(void) vmmdevIPort_VBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
4012{
4013 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4014 PVMMDEV pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVMMDEV);
4015 Log(("vmmdevIPort_VBVAChange: fEnabled = %d\n", fEnabled));
4016
4017 /* Only used by saved state, which I guess is why we don't bother with locking here. */
4018 pThis->u32VideoAccelEnabled = fEnabled;
4019}
4020
4021/**
4022 * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotUnplug}
4023 */
4024static DECLCALLBACK(int) vmmdevIPort_CpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
4025{
4026 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4027 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4028 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4029
4030 Log(("vmmdevIPort_CpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
4031
4032 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4033 AssertRCReturn(rc, rc);
4034
4035 if (pThis->fCpuHotPlugEventsEnabled)
4036 {
4037 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
4038 pThis->idCpuCore = idCpuCore;
4039 pThis->idCpuPackage = idCpuPackage;
4040 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_CPU_HOTPLUG);
4041 }
4042 else
4043 rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
4044
4045 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4046 return rc;
4047}
4048
4049/**
4050 * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotPlug}
4051 */
4052static DECLCALLBACK(int) vmmdevIPort_CpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
4053{
4054 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4055 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4056 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4057
4058 Log(("vmmdevCpuPlug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
4059
4060 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4061 AssertRCReturn(rc, rc);
4062
4063 if (pThis->fCpuHotPlugEventsEnabled)
4064 {
4065 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Plug;
4066 pThis->idCpuCore = idCpuCore;
4067 pThis->idCpuPackage = idCpuPackage;
4068 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_CPU_HOTPLUG);
4069 }
4070 else
4071 rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
4072
4073 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4074 return rc;
4075}
4076
4077
4078/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
4079
4080/**
4081 * @callback_method_impl{FNSSMDEVLIVEEXEC}
4082 */
4083static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4084{
4085 RT_NOREF(uPass);
4086 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4087 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4088
4089 pHlp->pfnSSMPutBool(pSSM, pThis->fGetHostTimeDisabled);
4090 pHlp->pfnSSMPutBool(pSSM, pThis->fBackdoorLogDisabled);
4091 pHlp->pfnSSMPutBool(pSSM, pThis->fKeepCredentials);
4092 pHlp->pfnSSMPutBool(pSSM, pThis->fHeapEnabled);
4093
4094 return VINF_SSM_DONT_CALL_AGAIN;
4095}
4096
4097
4098/**
4099 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4100 */
4101static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4102{
4103 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4104 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4105 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4106 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4107 AssertRCReturn(rc, rc);
4108
4109 vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
4110
4111 pHlp->pfnSSMPutU32(pSSM, 0 /*was pThis->hypervisorSize, which was always zero*/);
4112 pHlp->pfnSSMPutU32(pSSM, pThis->fMouseCapabilities);
4113 pHlp->pfnSSMPutS32(pSSM, pThis->xMouseAbs);
4114 pHlp->pfnSSMPutS32(pSSM, pThis->yMouseAbs);
4115 pHlp->pfnSSMPutS32(pSSM, pThis->dzMouse);
4116 pHlp->pfnSSMPutS32(pSSM, pThis->dwMouse);
4117 pHlp->pfnSSMPutU32(pSSM, pThis->fMouseButtons);
4118
4119 pHlp->pfnSSMPutBool(pSSM, pThis->fNewGuestFilterMaskValid);
4120 pHlp->pfnSSMPutU32(pSSM, pThis->fNewGuestFilterMask);
4121 pHlp->pfnSSMPutU32(pSSM, pThis->fGuestFilterMask);
4122 pHlp->pfnSSMPutU32(pSSM, pThis->fHostEventFlags);
4123 /* The following is not strictly necessary as PGM restores MMIO2, keeping it for historical reasons. */
4124 pHlp->pfnSSMPutMem(pSSM, &pThisCC->pVMMDevRAMR3->V, sizeof(pThisCC->pVMMDevRAMR3->V));
4125
4126 pHlp->pfnSSMPutMem(pSSM, &pThis->guestInfo, sizeof(pThis->guestInfo));
4127 pHlp->pfnSSMPutU32(pSSM, pThis->fu32AdditionsOk);
4128 pHlp->pfnSSMPutU32(pSSM, pThis->u32VideoAccelEnabled);
4129 pHlp->pfnSSMPutBool(pSSM, pThis->displayChangeData.fGuestSentChangeEventAck);
4130
4131 pHlp->pfnSSMPutU32(pSSM, pThis->fGuestCaps);
4132
4133#ifdef VBOX_WITH_HGCM
4134 vmmdevR3HgcmSaveState(pThisCC, pSSM);
4135#endif /* VBOX_WITH_HGCM */
4136
4137 pHlp->pfnSSMPutU32(pSSM, pThis->fHostCursorRequested);
4138
4139 pHlp->pfnSSMPutU32(pSSM, pThis->guestInfo2.uFullVersion);
4140 pHlp->pfnSSMPutU32(pSSM, pThis->guestInfo2.uRevision);
4141 pHlp->pfnSSMPutU32(pSSM, pThis->guestInfo2.fFeatures);
4142 pHlp->pfnSSMPutStrZ(pSSM, pThis->guestInfo2.szName);
4143 pHlp->pfnSSMPutU32(pSSM, pThis->cFacilityStatuses);
4144 for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++)
4145 {
4146 pHlp->pfnSSMPutU32(pSSM, pThis->aFacilityStatuses[i].enmFacility);
4147 pHlp->pfnSSMPutU32(pSSM, pThis->aFacilityStatuses[i].fFlags);
4148 pHlp->pfnSSMPutU16(pSSM, (uint16_t)pThis->aFacilityStatuses[i].enmStatus);
4149 pHlp->pfnSSMPutS64(pSSM, RTTimeSpecGetNano(&pThis->aFacilityStatuses[i].TimeSpecTS));
4150 }
4151
4152 /* Heartbeat: */
4153 pHlp->pfnSSMPutBool(pSSM, pThis->fHeartbeatActive);
4154 pHlp->pfnSSMPutBool(pSSM, pThis->fFlatlined);
4155 pHlp->pfnSSMPutU64(pSSM, pThis->nsLastHeartbeatTS);
4156 PDMDevHlpTimerSave(pDevIns, pThis->hFlatlinedTimer, pSSM);
4157
4158 pHlp->pfnSSMPutStructEx(pSSM, &pThis->displayChangeData, sizeof(pThis->displayChangeData), 0,
4159 g_aSSMDISPLAYCHANGEDATAStateFields, NULL);
4160
4161 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4162 return VINF_SUCCESS;
4163}
4164
4165/**
4166 * @callback_method_impl{FNSSMDEVLOADEXEC}
4167 */
4168static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4169{
4170 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4171 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4172 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4173 int rc;
4174
4175 if ( uVersion > VMMDEV_SAVED_STATE_VERSION
4176 || uVersion < 6)
4177 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4178
4179 /* config */
4180 if (uVersion > VMMDEV_SAVED_STATE_VERSION_VBOX_30)
4181 {
4182 bool f;
4183 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4184 if (pThis->fGetHostTimeDisabled != f)
4185 LogRel(("VMMDev: Config mismatch - fGetHostTimeDisabled: config=%RTbool saved=%RTbool\n", pThis->fGetHostTimeDisabled, f));
4186
4187 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4188 if (pThis->fBackdoorLogDisabled != f)
4189 LogRel(("VMMDev: Config mismatch - fBackdoorLogDisabled: config=%RTbool saved=%RTbool\n", pThis->fBackdoorLogDisabled, f));
4190
4191 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4192 if (pThis->fKeepCredentials != f)
4193 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fKeepCredentials: config=%RTbool saved=%RTbool"),
4194 pThis->fKeepCredentials, f);
4195 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4196 if (pThis->fHeapEnabled != f)
4197 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fHeapEnabled: config=%RTbool saved=%RTbool"),
4198 pThis->fHeapEnabled, f);
4199 }
4200
4201 if (uPass != SSM_PASS_FINAL)
4202 return VINF_SUCCESS;
4203
4204 /* state */
4205 uint32_t uIgn;
4206 pHlp->pfnSSMGetU32(pSSM, &uIgn);
4207 pHlp->pfnSSMGetU32(pSSM, &pThis->fMouseCapabilities);
4208 pHlp->pfnSSMGetS32(pSSM, &pThis->xMouseAbs);
4209 pHlp->pfnSSMGetS32(pSSM, &pThis->yMouseAbs);
4210 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_VMM_MOUSE_EXTENDED_DATA)
4211 {
4212 pHlp->pfnSSMGetS32(pSSM, &pThis->dzMouse);
4213 pHlp->pfnSSMGetS32(pSSM, &pThis->dwMouse);
4214 pHlp->pfnSSMGetU32(pSSM, &pThis->fMouseButtons);
4215 }
4216
4217 pHlp->pfnSSMGetBool(pSSM, &pThis->fNewGuestFilterMaskValid);
4218 pHlp->pfnSSMGetU32(pSSM, &pThis->fNewGuestFilterMask);
4219 pHlp->pfnSSMGetU32(pSSM, &pThis->fGuestFilterMask);
4220 pHlp->pfnSSMGetU32(pSSM, &pThis->fHostEventFlags);
4221
4222 //pHlp->pfnSSMGetBool(pSSM, &pThis->pVMMDevRAMR3->fHaveEvents);
4223 // here be dragons (probably)
4224 pHlp->pfnSSMGetMem(pSSM, &pThisCC->pVMMDevRAMR3->V, sizeof(pThisCC->pVMMDevRAMR3->V));
4225
4226 pHlp->pfnSSMGetMem(pSSM, &pThis->guestInfo, sizeof(pThis->guestInfo));
4227 pHlp->pfnSSMGetU32(pSSM, &pThis->fu32AdditionsOk);
4228 pHlp->pfnSSMGetU32(pSSM, &pThis->u32VideoAccelEnabled);
4229 if (uVersion > 10)
4230 pHlp->pfnSSMGetBool(pSSM, &pThis->displayChangeData.fGuestSentChangeEventAck);
4231
4232 rc = pHlp->pfnSSMGetU32(pSSM, &pThis->fGuestCaps);
4233
4234 /* Attributes which were temporarily introduced in r30072 */
4235 if (uVersion == 7)
4236 {
4237 uint32_t temp;
4238 pHlp->pfnSSMGetU32(pSSM, &temp);
4239 rc = pHlp->pfnSSMGetU32(pSSM, &temp);
4240 }
4241 AssertRCReturn(rc, rc);
4242
4243#ifdef VBOX_WITH_HGCM
4244 rc = vmmdevR3HgcmLoadState(pDevIns, pThis, pThisCC, pSSM, uVersion);
4245 AssertRCReturn(rc, rc);
4246#endif /* VBOX_WITH_HGCM */
4247
4248 if (uVersion >= 10)
4249 rc = pHlp->pfnSSMGetU32(pSSM, &pThis->fHostCursorRequested);
4250 AssertRCReturn(rc, rc);
4251
4252 if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2)
4253 {
4254 pHlp->pfnSSMGetU32(pSSM, &pThis->guestInfo2.uFullVersion);
4255 pHlp->pfnSSMGetU32(pSSM, &pThis->guestInfo2.uRevision);
4256 pHlp->pfnSSMGetU32(pSSM, &pThis->guestInfo2.fFeatures);
4257 rc = pHlp->pfnSSMGetStrZ(pSSM, &pThis->guestInfo2.szName[0], sizeof(pThis->guestInfo2.szName));
4258 AssertRCReturn(rc, rc);
4259 }
4260
4261 if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES)
4262 {
4263 uint32_t cFacilityStatuses;
4264 rc = pHlp->pfnSSMGetU32(pSSM, &cFacilityStatuses);
4265 AssertRCReturn(rc, rc);
4266
4267 for (uint32_t i = 0; i < cFacilityStatuses; i++)
4268 {
4269 uint32_t uFacility, fFlags;
4270 uint16_t uStatus;
4271 int64_t iTimeStampNano;
4272
4273 pHlp->pfnSSMGetU32(pSSM, &uFacility);
4274 pHlp->pfnSSMGetU32(pSSM, &fFlags);
4275 pHlp->pfnSSMGetU16(pSSM, &uStatus);
4276 rc = pHlp->pfnSSMGetS64(pSSM, &iTimeStampNano);
4277 AssertRCReturn(rc, rc);
4278
4279 PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, (VBoxGuestFacilityType)uFacility);
4280 AssertLogRelMsgReturn(pEntry,
4281 ("VMMDev: Ran out of entries restoring the guest facility statuses. Saved state has %u.\n", cFacilityStatuses),
4282 VERR_OUT_OF_RESOURCES);
4283 pEntry->enmStatus = (VBoxGuestFacilityStatus)uStatus;
4284 pEntry->fFlags = fFlags;
4285 RTTimeSpecSetNano(&pEntry->TimeSpecTS, iTimeStampNano);
4286 }
4287 }
4288
4289 /*
4290 * Heartbeat.
4291 */
4292 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_HEARTBEAT)
4293 {
4294 pHlp->pfnSSMGetBoolV(pSSM, &pThis->fHeartbeatActive);
4295 pHlp->pfnSSMGetBoolV(pSSM, &pThis->fFlatlined);
4296 pHlp->pfnSSMGetU64V(pSSM, &pThis->nsLastHeartbeatTS);
4297 rc = PDMDevHlpTimerLoad(pDevIns, pThis->hFlatlinedTimer, pSSM);
4298 AssertRCReturn(rc, rc);
4299 if (pThis->fFlatlined)
4300 LogRel(("vmmdevLoadState: Guest has flatlined. Last heartbeat %'RU64 ns before state was saved.\n",
4301 PDMDevHlpTimerGetNano(pDevIns, pThis->hFlatlinedTimer) - pThis->nsLastHeartbeatTS));
4302 }
4303
4304 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_DISPLAY_CHANGE_DATA)
4305 {
4306 pHlp->pfnSSMGetStructEx(pSSM, &pThis->displayChangeData, sizeof(pThis->displayChangeData), 0,
4307 g_aSSMDISPLAYCHANGEDATAStateFields, NULL);
4308 }
4309
4310 /*
4311 * On a resume, we send the capabilities changed message so
4312 * that listeners can sync their state again
4313 */
4314 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pThis->fMouseCapabilities));
4315 if (pThisCC->pDrv)
4316 {
4317 pThisCC->pDrv->pfnUpdateMouseCapabilities(pThisCC->pDrv, pThis->fMouseCapabilities);
4318 if (uVersion >= 10)
4319 pThisCC->pDrv->pfnUpdatePointerShape(pThisCC->pDrv,
4320 /*fVisible=*/!!pThis->fHostCursorRequested,
4321 /*fAlpha=*/false,
4322 /*xHot=*/0, /*yHot=*/0,
4323 /*cx=*/0, /*cy=*/0,
4324 /*pvShape=*/NULL);
4325 }
4326
4327 if (pThis->fu32AdditionsOk)
4328 {
4329 vmmdevLogGuestOsInfo(&pThis->guestInfo);
4330 if (pThisCC->pDrv)
4331 {
4332 if (pThis->guestInfo2.uFullVersion && pThisCC->pDrv->pfnUpdateGuestInfo2)
4333 pThisCC->pDrv->pfnUpdateGuestInfo2(pThisCC->pDrv, pThis->guestInfo2.uFullVersion, pThis->guestInfo2.szName,
4334 pThis->guestInfo2.uRevision, pThis->guestInfo2.fFeatures);
4335 if (pThisCC->pDrv->pfnUpdateGuestInfo)
4336 pThisCC->pDrv->pfnUpdateGuestInfo(pThisCC->pDrv, &pThis->guestInfo);
4337
4338 if (pThisCC->pDrv->pfnUpdateGuestStatus)
4339 {
4340 for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++) /* ascending order! */
4341 if ( pThis->aFacilityStatuses[i].enmStatus != VBoxGuestFacilityStatus_Inactive
4342 || !pThis->aFacilityStatuses[i].fFixed)
4343 pThisCC->pDrv->pfnUpdateGuestStatus(pThisCC->pDrv,
4344 pThis->aFacilityStatuses[i].enmFacility,
4345 (uint16_t)pThis->aFacilityStatuses[i].enmStatus,
4346 pThis->aFacilityStatuses[i].fFlags,
4347 &pThis->aFacilityStatuses[i].TimeSpecTS);
4348 }
4349 }
4350 }
4351 if (pThisCC->pDrv && pThisCC->pDrv->pfnUpdateGuestCapabilities)
4352 pThisCC->pDrv->pfnUpdateGuestCapabilities(pThisCC->pDrv, pThis->fGuestCaps);
4353
4354 return VINF_SUCCESS;
4355}
4356
4357/**
4358 * Load state done callback. Notify guest of restore event.
4359 *
4360 * @returns VBox status code.
4361 * @param pDevIns The device instance.
4362 * @param pSSM The handle to the saved state.
4363 */
4364static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4365{
4366 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4367 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4368 RT_NOREF(pSSM);
4369
4370#ifdef VBOX_WITH_HGCM
4371 int rc = vmmdevR3HgcmLoadStateDone(pDevIns, pThis, pThisCC);
4372 AssertLogRelRCReturn(rc, rc);
4373#endif /* VBOX_WITH_HGCM */
4374
4375 /* Reestablish the acceleration status. */
4376 if ( pThis->u32VideoAccelEnabled
4377 && pThisCC->pDrv)
4378 pThisCC->pDrv->pfnVideoAccelEnable(pThisCC->pDrv, !!pThis->u32VideoAccelEnabled, &pThisCC->pVMMDevRAMR3->vbvaMemory);
4379
4380 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_RESTORED);
4381
4382 return VINF_SUCCESS;
4383}
4384
4385
4386/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
4387
4388/**
4389 * (Re-)initializes the MMIO2 data.
4390 *
4391 * @param pThisCC The VMMDev ring-3 instance data.
4392 */
4393static void vmmdevInitRam(PVMMDEVCC pThisCC)
4394{
4395 memset(pThisCC->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
4396 pThisCC->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
4397 pThisCC->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
4398}
4399
4400
4401/**
4402 * @interface_method_impl{PDMDEVREG,pfnReset}
4403 */
4404static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
4405{
4406 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4407 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4408 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4409 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
4410
4411 /*
4412 * Reset the mouse integration feature bits
4413 */
4414 if (pThis->fMouseCapabilities & VMMDEV_MOUSE_GUEST_MASK)
4415 {
4416 pThis->fMouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
4417 /* notify the connector */
4418 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pThis->fMouseCapabilities));
4419 pThisCC->pDrv->pfnUpdateMouseCapabilities(pThisCC->pDrv, pThis->fMouseCapabilities);
4420 }
4421 pThis->fHostCursorRequested = false;
4422
4423 /* re-initialize the VMMDev memory */
4424 if (pThisCC->pVMMDevRAMR3)
4425 vmmdevInitRam(pThisCC);
4426
4427 /* credentials have to go away (by default) */
4428 VMMDEVCREDS *pCredentials = pThisCC->pCredentials;
4429 if (pCredentials)
4430 {
4431 if (!pThis->fKeepCredentials)
4432 {
4433 RT_ZERO(pCredentials->Logon.szUserName);
4434 RT_ZERO(pCredentials->Logon.szPassword);
4435 RT_ZERO(pCredentials->Logon.szDomain);
4436 }
4437 RT_ZERO(pCredentials->Judge.szUserName);
4438 RT_ZERO(pCredentials->Judge.szPassword);
4439 RT_ZERO(pCredentials->Judge.szDomain);
4440 }
4441
4442 /* Reset means that additions will report again. */
4443 const bool fVersionChanged = pThis->fu32AdditionsOk
4444 || pThis->guestInfo.interfaceVersion
4445 || pThis->guestInfo.osType != VBOXOSTYPE_Unknown;
4446 if (fVersionChanged)
4447 Log(("vmmdevReset: fu32AdditionsOk=%d additionsVersion=%x osType=%#x\n",
4448 pThis->fu32AdditionsOk, pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
4449 pThis->fu32AdditionsOk = false;
4450 memset (&pThis->guestInfo, 0, sizeof (pThis->guestInfo));
4451 RT_ZERO(pThis->guestInfo2);
4452 const bool fCapsChanged = pThis->fGuestCaps != 0; /* Report transition to 0. */
4453 pThis->fGuestCaps = 0;
4454
4455 /* Clear facilities. No need to tell Main as it will get a
4456 pfnUpdateGuestInfo callback. */
4457 RTTIMESPEC TimeStampNow;
4458 RTTimeNow(&TimeStampNow);
4459 uint32_t iFacility = pThis->cFacilityStatuses;
4460 while (iFacility-- > 0)
4461 {
4462 pThis->aFacilityStatuses[iFacility].enmStatus = VBoxGuestFacilityStatus_Inactive;
4463 pThis->aFacilityStatuses[iFacility].TimeSpecTS = TimeStampNow;
4464 }
4465
4466 /* clear pending display change request. */
4467 for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
4468 {
4469 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
4470 memset(&pRequest->lastReadDisplayChangeRequest, 0, sizeof(pRequest->lastReadDisplayChangeRequest));
4471 pRequest->lastReadDisplayChangeRequest.fDisplayFlags = VMMDEV_DISPLAY_DISABLED;
4472 pRequest->lastReadDisplayChangeRequest.idDisplay = i;
4473 }
4474 pThis->displayChangeData.iCurrentMonitor = 0;
4475 pThis->displayChangeData.fGuestSentChangeEventAck = false;
4476
4477 /* disable seamless mode */
4478 pThis->fLastSeamlessEnabled = false;
4479
4480 /* disabled memory ballooning */
4481 pThis->cMbMemoryBalloonLast = 0;
4482
4483 /* disabled statistics updating */
4484 pThis->cSecsLastStatInterval = 0;
4485
4486#ifdef VBOX_WITH_HGCM
4487 /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled. */
4488 pThisCC->u32HGCMEnabled = 0;
4489#endif
4490
4491 /*
4492 * Deactive heartbeat.
4493 */
4494 if (pThis->fHeartbeatActive)
4495 {
4496 PDMDevHlpTimerStop(pDevIns, pThis->hFlatlinedTimer);
4497 pThis->fFlatlined = false;
4498 pThis->fHeartbeatActive = true;
4499 }
4500
4501 /*
4502 * Clear the event variables.
4503 *
4504 * XXX By design we should NOT clear pThis->fHostEventFlags because it is designed
4505 * that way so host events do not depend on guest resets. However, the pending
4506 * event flags actually _were_ cleared since ages so we mask out events from
4507 * clearing which we really need to survive the reset. See xtracker 5767.
4508 */
4509 pThis->fHostEventFlags &= VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
4510 pThis->fGuestFilterMask = 0;
4511 pThis->fNewGuestFilterMask = 0;
4512 pThis->fNewGuestFilterMaskValid = 0;
4513
4514 /*
4515 * Call the update functions as required.
4516 */
4517 if (fVersionChanged && pThisCC->pDrv && pThisCC->pDrv->pfnUpdateGuestInfo)
4518 pThisCC->pDrv->pfnUpdateGuestInfo(pThisCC->pDrv, &pThis->guestInfo);
4519 if (fCapsChanged && pThisCC->pDrv && pThisCC->pDrv->pfnUpdateGuestCapabilities)
4520 pThisCC->pDrv->pfnUpdateGuestCapabilities(pThisCC->pDrv, pThis->fGuestCaps);
4521
4522 /*
4523 * Generate a unique session id for this VM; it will be changed for each start, reset or restore.
4524 * This can be used for restore detection inside the guest.
4525 */
4526 pThis->idSession = ASMReadTSC();
4527
4528 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4529}
4530
4531
4532#ifdef VBOX_WITH_RAW_MODE_KEEP
4533/**
4534 * @interface_method_impl{PDMDEVREG,pfnRelocate}
4535 */
4536static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
4537{
4538 if (offDelta)
4539 {
4540 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4541 LogFlow(("vmmdevRelocate: offDelta=%RGv\n", offDelta));
4542
4543 if (pThis->pVMMDevRAMRC)
4544 pThis->pVMMDevRAMRC += offDelta;
4545 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
4546 }
4547}
4548#endif
4549
4550
4551/**
4552 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4553 */
4554static DECLCALLBACK(int) vmmdevDestruct(PPDMDEVINS pDevIns)
4555{
4556 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4557 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4558
4559 /*
4560 * Wipe and free the credentials.
4561 */
4562 VMMDEVCREDS *pCredentials = pThisCC->pCredentials;
4563 pThisCC->pCredentials = NULL;
4564 if (pCredentials)
4565 {
4566 if (pThisCC->fSaferCredentials)
4567 RTMemSaferFree(pCredentials, sizeof(*pCredentials));
4568 else
4569 {
4570 RTMemWipeThoroughly(pCredentials, sizeof(*pCredentials), 10);
4571 RTMemFree(pCredentials);
4572 }
4573 }
4574
4575#ifdef VBOX_WITH_HGCM
4576 /*
4577 * Everything HGCM.
4578 */
4579 vmmdevR3HgcmDestroy(pDevIns, PDMDEVINS_2_DATA(pDevIns, PVMMDEV), pThisCC);
4580#endif
4581
4582 /*
4583 * Free the request buffers.
4584 */
4585 for (uint32_t iCpu = 0; iCpu < RT_ELEMENTS(pThisCC->apReqBufs); iCpu++)
4586 {
4587 RTMemPageFree(pThisCC->apReqBufs[iCpu], _4K);
4588 pThisCC->apReqBufs[iCpu] = NULL;
4589 }
4590
4591#ifndef VBOX_WITHOUT_TESTING_FEATURES
4592 /*
4593 * Clean up the testing device.
4594 */
4595 vmmdevR3TestingTerminate(pDevIns);
4596#endif
4597
4598 return VINF_SUCCESS;
4599}
4600
4601
4602/**
4603 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4604 */
4605static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4606{
4607 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4608 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4609 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4610 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4611 int rc;
4612
4613 Assert(iInstance == 0);
4614 RT_NOREF(iInstance);
4615
4616 /*
4617 * Initialize data (most of it anyway).
4618 */
4619 pThisCC->pDevIns = pDevIns;
4620
4621 pThis->hFlatlinedTimer = NIL_TMTIMERHANDLE;
4622 pThis->hIoPortBackdoorLog = NIL_IOMIOPORTHANDLE;
4623 pThis->hIoPortAltTimesync = NIL_IOMIOPORTHANDLE;
4624 pThis->hIoPortReq = NIL_IOMIOPORTHANDLE;
4625 pThis->hIoPortFast = NIL_IOMIOPORTHANDLE;
4626 pThis->hMmio2VMMDevRAM = NIL_PGMMMIO2HANDLE;
4627 pThis->hMmio2Heap = NIL_PGMMMIO2HANDLE;
4628#ifndef VBOX_WITHOUT_TESTING_FEATURES
4629 pThis->hIoPortTesting = NIL_IOMIOPORTHANDLE;
4630 pThis->hMmioTesting = NIL_IOMMMIOHANDLE;
4631 pThis->hTestingLockEvt = NIL_SUPSEMEVENT;
4632#endif
4633
4634 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4635 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
4636
4637 /* PCI vendor, just a free bogus value */
4638 PDMPciDevSetVendorId(pPciDev, 0x80ee);
4639 /* device ID */
4640 PDMPciDevSetDeviceId(pPciDev, 0xcafe);
4641 /* class sub code (other type of system peripheral) */
4642 PDMPciDevSetClassSub(pPciDev, 0x80);
4643 /* class base code (base system peripheral) */
4644 PDMPciDevSetClassBase(pPciDev, 0x08);
4645 /* header type */
4646 PDMPciDevSetHeaderType(pPciDev, 0x00);
4647 /* interrupt on pin 0 */
4648 PDMPciDevSetInterruptPin(pPciDev, 0x01);
4649
4650 RTTIMESPEC TimeStampNow;
4651 RTTimeNow(&TimeStampNow);
4652 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxGuestDriver, true /*fFixed*/, &TimeStampNow);
4653 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxService, true /*fFixed*/, &TimeStampNow);
4654 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxTrayClient, true /*fFixed*/, &TimeStampNow);
4655 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Seamless, true /*fFixed*/, &TimeStampNow);
4656 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Graphics, true /*fFixed*/, &TimeStampNow);
4657 Assert(pThis->cFacilityStatuses == 5);
4658
4659 /* disable all screens (no better hints known yet). */
4660 /** @todo r=klaus need a way to represent "no hint known" */
4661 for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
4662 {
4663 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
4664 pRequest->displayChangeRequest.fDisplayFlags = VMMDEV_DISPLAY_DISABLED;
4665 pRequest->displayChangeRequest.idDisplay = i;
4666 pRequest->lastReadDisplayChangeRequest.fDisplayFlags = VMMDEV_DISPLAY_DISABLED;
4667 pRequest->lastReadDisplayChangeRequest.idDisplay = i;
4668 }
4669
4670 /*
4671 * Interfaces
4672 */
4673 /* IBase */
4674 pThisCC->IBase.pfnQueryInterface = vmmdevPortQueryInterface;
4675
4676 /* VMMDev port */
4677 pThisCC->IPort.pfnQueryAbsoluteMouse = vmmdevIPort_QueryAbsoluteMouse;
4678 pThisCC->IPort.pfnSetAbsoluteMouse = vmmdevIPort_SetAbsoluteMouse ;
4679 pThisCC->IPort.pfnQueryMouseCapabilities = vmmdevIPort_QueryMouseCapabilities;
4680 pThisCC->IPort.pfnUpdateMouseCapabilities = vmmdevIPort_UpdateMouseCapabilities;
4681 pThisCC->IPort.pfnRequestDisplayChange = vmmdevIPort_RequestDisplayChange;
4682 pThisCC->IPort.pfnSetCredentials = vmmdevIPort_SetCredentials;
4683 pThisCC->IPort.pfnVBVAChange = vmmdevIPort_VBVAChange;
4684 pThisCC->IPort.pfnRequestSeamlessChange = vmmdevIPort_RequestSeamlessChange;
4685 pThisCC->IPort.pfnSetMemoryBalloon = vmmdevIPort_SetMemoryBalloon;
4686 pThisCC->IPort.pfnSetStatisticsInterval = vmmdevIPort_SetStatisticsInterval;
4687 pThisCC->IPort.pfnVRDPChange = vmmdevIPort_VRDPChange;
4688 pThisCC->IPort.pfnCpuHotUnplug = vmmdevIPort_CpuHotUnplug;
4689 pThisCC->IPort.pfnCpuHotPlug = vmmdevIPort_CpuHotPlug;
4690
4691 /* Shared folder LED */
4692 pThisCC->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
4693 pThisCC->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
4694
4695#ifdef VBOX_WITH_HGCM
4696 /* HGCM port */
4697 pThisCC->IHGCMPort.pfnCompleted = hgcmR3Completed;
4698 pThisCC->IHGCMPort.pfnIsCmdRestored = hgcmR3IsCmdRestored;
4699 pThisCC->IHGCMPort.pfnIsCmdCancelled = hgcmR3IsCmdCancelled;
4700 pThisCC->IHGCMPort.pfnGetRequestor = hgcmR3GetRequestor;
4701 pThisCC->IHGCMPort.pfnGetVMMDevSessionId = hgcmR3GetVMMDevSessionId;
4702#endif
4703
4704 pThisCC->pCredentials = (VMMDEVCREDS *)RTMemSaferAllocZ(sizeof(*pThisCC->pCredentials));
4705 if (pThisCC->pCredentials)
4706 pThisCC->fSaferCredentials = true;
4707 else
4708 {
4709 pThisCC->pCredentials = (VMMDEVCREDS *)RTMemAllocZ(sizeof(*pThisCC->pCredentials));
4710 AssertReturn(pThisCC->pCredentials, VERR_NO_MEMORY);
4711 }
4712
4713
4714 /*
4715 * Validate and read the configuration.
4716 */
4717 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
4718 "AllowGuestToSaveState|"
4719 "GetHostTimeDisabled|"
4720 "BackdoorLogDisabled|"
4721 "KeepCredentials|"
4722 "HeapEnabled|"
4723 "GuestCoreDumpEnabled|"
4724 "GuestCoreDumpDir|"
4725 "GuestCoreDumpCount|"
4726 "HeartbeatInterval|"
4727 "HeartbeatTimeout|"
4728 "TestingEnabled|"
4729 "TestingMMIO|"
4730 "TestingXmlOutputFile|"
4731 "TestingCfgDword0|"
4732 "TestingCfgDword1|"
4733 "TestingCfgDword2|"
4734 "TestingCfgDword3|"
4735 "TestingCfgDword4|"
4736 "TestingCfgDword5|"
4737 "TestingCfgDword6|"
4738 "TestingCfgDword7|"
4739 "TestingCfgDword8|"
4740 "TestingCfgDword9|"
4741 "HGCMHeapBudgetDefault|"
4742 "HGCMHeapBudgetLegacy|"
4743 "HGCMHeapBudgetVBoxGuest|"
4744 "HGCMHeapBudgetOtherDrv|"
4745 "HGCMHeapBudgetRoot|"
4746 "HGCMHeapBudgetSystem|"
4747 "HGCMHeapBudgetReserved1|"
4748 "HGCMHeapBudgetUser|"
4749 "HGCMHeapBudgetGuest"
4750 ,
4751 "");
4752
4753 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "AllowGuestToSaveState", &pThis->fAllowGuestToSaveState, true);
4754 if (RT_FAILURE(rc))
4755 return PDMDEV_SET_ERROR(pDevIns, rc,
4756 N_("Configuration error: Failed querying \"AllowGuestToSaveState\" as a boolean"));
4757
4758 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
4759 if (RT_FAILURE(rc))
4760 return PDMDEV_SET_ERROR(pDevIns, rc,
4761 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
4762
4763 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "BackdoorLogDisabled", &pThis->fBackdoorLogDisabled, false);
4764 if (RT_FAILURE(rc))
4765 return PDMDEV_SET_ERROR(pDevIns, rc,
4766 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
4767
4768 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "KeepCredentials", &pThis->fKeepCredentials, false);
4769 if (RT_FAILURE(rc))
4770 return PDMDEV_SET_ERROR(pDevIns, rc,
4771 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
4772
4773 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "HeapEnabled", &pThis->fHeapEnabled, true);
4774 if (RT_FAILURE(rc))
4775 return PDMDEV_SET_ERROR(pDevIns, rc,
4776 N_("Configuration error: Failed querying \"HeapEnabled\" as a boolean"));
4777
4778 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "GuestCoreDumpEnabled", &pThis->fGuestCoreDumpEnabled, false);
4779 if (RT_FAILURE(rc))
4780 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"GuestCoreDumpEnabled\" as a boolean"));
4781
4782 char *pszGuestCoreDumpDir = NULL;
4783 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "GuestCoreDumpDir", &pszGuestCoreDumpDir, "");
4784 if (RT_FAILURE(rc))
4785 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"GuestCoreDumpDir\" as a string"));
4786
4787 RTStrCopy(pThis->szGuestCoreDumpDir, sizeof(pThis->szGuestCoreDumpDir), pszGuestCoreDumpDir);
4788 PDMDevHlpMMHeapFree(pDevIns, pszGuestCoreDumpDir);
4789
4790 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GuestCoreDumpCount", &pThis->cGuestCoreDumps, 3);
4791 if (RT_FAILURE(rc))
4792 return PDMDEV_SET_ERROR(pDevIns, rc,
4793 N_("Configuration error: Failed querying \"GuestCoreDumpCount\" as a 32-bit unsigned integer"));
4794
4795 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "HeartbeatInterval", &pThis->cNsHeartbeatInterval, VMMDEV_HEARTBEAT_DEFAULT_INTERVAL);
4796 if (RT_FAILURE(rc))
4797 return PDMDEV_SET_ERROR(pDevIns, rc,
4798 N_("Configuration error: Failed querying \"HeartbeatInterval\" as a 64-bit unsigned integer"));
4799 if (pThis->cNsHeartbeatInterval < RT_NS_100MS / 2)
4800 return PDMDEV_SET_ERROR(pDevIns, rc,
4801 N_("Configuration error: Heartbeat interval \"HeartbeatInterval\" too small"));
4802
4803 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "HeartbeatTimeout", &pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval * 2);
4804 if (RT_FAILURE(rc))
4805 return PDMDEV_SET_ERROR(pDevIns, rc,
4806 N_("Configuration error: Failed querying \"HeartbeatTimeout\" as a 64-bit unsigned integer"));
4807 if (pThis->cNsHeartbeatTimeout < RT_NS_100MS)
4808 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" too small"));
4809 if (pThis->cNsHeartbeatTimeout <= pThis->cNsHeartbeatInterval + RT_NS_10MS)
4810 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4811 N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" value (%'ull ns) is too close to the interval (%'ull ns)"),
4812 pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval);
4813
4814#ifndef VBOX_WITHOUT_TESTING_FEATURES
4815 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TestingEnabled", &pThis->fTestingEnabled, false);
4816 if (RT_FAILURE(rc))
4817 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestingEnabled\" as a boolean"));
4818 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TestingMMIO", &pThis->fTestingMMIO, false);
4819 if (RT_FAILURE(rc))
4820 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestingMMIO\" as a boolean"));
4821 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "TestingXmlOutputFile", &pThisCC->pszTestingXmlOutput, NULL);
4822 if (RT_FAILURE(rc))
4823 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestingXmlOutputFile\" as a string"));
4824
4825 for (unsigned i = 0; i < RT_ELEMENTS(pThis->au32TestingCfgDwords); i++)
4826 {
4827 char szName[32];
4828 RTStrPrintf(szName, sizeof(szName), "TestingCfgDword%u", i);
4829 rc = pHlp->pfnCFGMQueryU32Def(pCfg, szName, &pThis->au32TestingCfgDwords[i], 0);
4830 if (RT_FAILURE(rc))
4831 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4832 N_("Configuration error: Failed querying \"%s\" as a string"), szName);
4833 }
4834
4835
4836 /** @todo image-to-load-filename? */
4837#endif
4838
4839#ifdef VBOX_WITH_HGCM
4840 /*
4841 * Heap budgets for HGCM requestor categories. Take the available host
4842 * memory as a rough hint of how much we can handle.
4843 */
4844 uint64_t cbDefaultBudget = 0;
4845 if (RT_FAILURE(RTSystemQueryTotalRam(&cbDefaultBudget)))
4846 cbDefaultBudget = 8 * _1G64;
4847 LogFunc(("RTSystemQueryTotalRam -> %'RU64 (%RX64)\n", cbDefaultBudget, cbDefaultBudget));
4848# if ARCH_BITS == 32
4849 cbDefaultBudget = RT_MIN(cbDefaultBudget, _512M);
4850# endif
4851 cbDefaultBudget /= 8; /* One eighth of physical memory ... */
4852 cbDefaultBudget /= RT_ELEMENTS(pThisCC->aHgcmAcc); /* over 3 accounting categories. (8GiB -> 341MiB) */
4853 cbDefaultBudget = RT_MIN(cbDefaultBudget, _1G); /* max 1024MiB */
4854 cbDefaultBudget = RT_MAX(cbDefaultBudget, _32M); /* min 32MiB */
4855 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "HGCMHeapBudgetDefault", &cbDefaultBudget, cbDefaultBudget);
4856 if (RT_FAILURE(rc))
4857 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"HGCMHeapBudgetDefault\" as a 64-bit unsigned integer"));
4858
4859 LogRel(("VMMDev: cbDefaultBudget: %'RU64 (%RX64)\n", cbDefaultBudget, cbDefaultBudget));
4860 static const struct { const char *pszName; unsigned idx; } s_aCfgHeapBudget[] =
4861 {
4862 { "HGCMHeapBudgetKernel", VMMDEV_HGCM_CATEGORY_KERNEL },
4863 { "HGCMHeapBudgetRoot", VMMDEV_HGCM_CATEGORY_ROOT },
4864 { "HGCMHeapBudgetUser", VMMDEV_HGCM_CATEGORY_USER },
4865 };
4866 AssertCompile(RT_ELEMENTS(s_aCfgHeapBudget) == RT_ELEMENTS(pThisCC->aHgcmAcc));
4867 for (uintptr_t i = 0; i < RT_ELEMENTS(s_aCfgHeapBudget); i++)
4868 {
4869 uintptr_t const idx = s_aCfgHeapBudget[i].idx;
4870 rc = pHlp->pfnCFGMQueryU64Def(pCfg, s_aCfgHeapBudget[i].pszName,
4871 &pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig, cbDefaultBudget);
4872 if (RT_FAILURE(rc))
4873 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4874 N_("Configuration error: Failed querying \"%s\" as a 64-bit unsigned integer"),
4875 s_aCfgHeapBudget[i].pszName);
4876 pThisCC->aHgcmAcc[idx].cbHeapBudget = pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig;
4877 if (pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig != cbDefaultBudget)
4878 LogRel(("VMMDev: %s: %'RU64 (%#RX64)\n", s_aCfgHeapBudget[i].pszName,
4879 pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig, pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig));
4880
4881 const char * const pszCatName = &s_aCfgHeapBudget[i].pszName[sizeof("HGCMHeapBudget") - 1];
4882 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].cbHeapBudget, STAMTYPE_U64, STAMVISIBILITY_ALWAYS,
4883 STAMUNIT_BYTES, "Currently available budget", "HGCM-%s/BudgetAvailable", pszCatName);
4884 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig, STAMTYPE_U64, STAMVISIBILITY_ALWAYS,
4885 STAMUNIT_BYTES, "Configured budget", "HGCM-%s/BudgetConfig", pszCatName);
4886 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].StateMsgHeapUsage, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
4887 STAMUNIT_BYTES_PER_CALL, "Message heap usage", "HGCM-%s/MessageHeapUsage", pszCatName);
4888 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].StatBudgetOverruns, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
4889 STAMUNIT_BYTES, "Budget overruns and allocation errors", "HGCM-%s/BudgetOverruns", pszCatName);
4890 }
4891#endif
4892
4893 /*
4894 * <missing comment>
4895 */
4896 pThis->cbGuestRAM = PDMDevHlpMMPhysGetRamSize(pDevIns);
4897
4898 /*
4899 * We do our own locking entirely. So, install NOP critsect for the device
4900 * and create our own critsect for use where it really matters (++).
4901 */
4902 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4903 AssertRCReturn(rc, rc);
4904 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev#%u", iInstance);
4905 AssertRCReturn(rc, rc);
4906
4907 /*
4908 * Register the backdoor logging port
4909 */
4910 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, RTLOG_DEBUG_PORT, 1, vmmdevBackdoorLog, NULL /*pfnIn*/,
4911 "VMMDev backdoor logging", NULL, &pThis->hIoPortBackdoorLog);
4912 AssertRCReturn(rc, rc);
4913
4914#ifdef VMMDEV_WITH_ALT_TIMESYNC
4915 /*
4916 * Alternative timesync source.
4917 *
4918 * This was orignally added for creating a simple time sync service in an
4919 * OpenBSD guest without requiring VBoxGuest and VBoxService to be ported
4920 * first. We keep it in case it comes in handy.
4921 */
4922 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x505, 1, vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead,
4923 "VMMDev timesync backdoor", NULL /*paExtDescs*/, &pThis->hIoPortAltTimesync);
4924 AssertRCReturn(rc, rc);
4925#endif
4926
4927 /*
4928 * Register the PCI device.
4929 */
4930 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
4931 if (RT_FAILURE(rc))
4932 return rc;
4933 if (pPciDev->uDevFn != 32 || iInstance != 0)
4934 Log(("!!WARNING!!: pThis->PciDev.uDevFn=%d (ignore if testcase or no started by Main)\n", pPciDev->uDevFn));
4935
4936 /*
4937 * The I/O ports, PCI region #0. This has two separate I/O port mappings in it,
4938 * so we have to do it via the mapper callback.
4939 */
4940 rc = PDMDevHlpIoPortCreate(pDevIns, 1 /*cPorts*/, pPciDev, RT_MAKE_U32(0, 0), vmmdevRequestHandler, NULL /*pfnIn*/,
4941 NULL /*pvUser*/, "VMMDev Request Handler", NULL, &pThis->hIoPortReq);
4942 AssertRCReturn(rc, rc);
4943
4944 rc = PDMDevHlpIoPortCreate(pDevIns, 1 /*cPorts*/, pPciDev, RT_MAKE_U32(1, 0), vmmdevFastRequestHandler,
4945 vmmdevFastRequestIrqAck, NULL, "VMMDev Fast R0/RC Requests", NULL /*pvUser*/, &pThis->hIoPortFast);
4946 AssertRCReturn(rc, rc);
4947
4948 rc = PDMDevHlpPCIIORegionRegisterIoCustom(pDevIns, 0, 0x20, vmmdevIOPortRegionMap);
4949 AssertRCReturn(rc, rc);
4950
4951 /*
4952 * Allocate and initialize the MMIO2 memory, PCI region #1.
4953 */
4954 rc = PDMDevHlpPCIIORegionCreateMmio2(pDevIns, 1 /*iPciRegion*/, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, "VMMDev",
4955 (void **)&pThisCC->pVMMDevRAMR3, &pThis->hMmio2VMMDevRAM);
4956 if (RT_FAILURE(rc))
4957 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4958 N_("Failed to create the %u (%#x) byte MMIO2 region for the VMM device"),
4959 VMMDEV_RAM_SIZE, VMMDEV_RAM_SIZE);
4960 vmmdevInitRam(pThisCC);
4961
4962 /*
4963 * The MMIO2 heap (used for real-mode VT-x trickery), PCI region #2.
4964 */
4965 if (pThis->fHeapEnabled)
4966 {
4967 rc = PDMDevHlpPCIIORegionCreateMmio2Ex(pDevIns, 2 /*iPciRegion*/, VMMDEV_HEAP_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH,
4968 0 /*fFlags*/, vmmdevMmio2HeapRegionMap, "VMMDev Heap",
4969 (void **)&pThisCC->pVMMDevHeapR3, &pThis->hMmio2Heap);
4970 if (RT_FAILURE(rc))
4971 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4972 N_("Failed to create the %u (%#x) bytes MMIO2 heap region for the VMM device"),
4973 VMMDEV_HEAP_SIZE, VMMDEV_HEAP_SIZE);
4974
4975 /* Register the memory area with PDM so HM can access it before it's mapped. */
4976 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThisCC->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
4977 AssertLogRelRCReturn(rc, rc);
4978 }
4979
4980#ifndef VBOX_WITHOUT_TESTING_FEATURES
4981 /*
4982 * Initialize testing.
4983 */
4984 rc = vmmdevR3TestingInitialize(pDevIns);
4985 if (RT_FAILURE(rc))
4986 return rc;
4987#endif
4988
4989 /*
4990 * Get the corresponding connector interface
4991 */
4992 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "VMM Driver Port");
4993 if (RT_SUCCESS(rc))
4994 {
4995 pThisCC->pDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIVMMDEVCONNECTOR);
4996 AssertMsgReturn(pThisCC->pDrv, ("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
4997#ifdef VBOX_WITH_HGCM
4998 pThisCC->pHGCMDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIHGCMCONNECTOR);
4999 if (!pThisCC->pHGCMDrv)
5000 {
5001 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Rrc\n", rc));
5002 /* this is not actually an error, just means that there is no support for HGCM */
5003 }
5004#endif
5005 /* Query the initial balloon size. */
5006 AssertPtr(pThisCC->pDrv->pfnQueryBalloonSize);
5007 rc = pThisCC->pDrv->pfnQueryBalloonSize(pThisCC->pDrv, &pThis->cMbMemoryBalloon);
5008 AssertRC(rc);
5009
5010 Log(("Initial balloon size %x\n", pThis->cMbMemoryBalloon));
5011 }
5012 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5013 {
5014 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
5015 rc = VINF_SUCCESS;
5016 }
5017 else
5018 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Rrc\n", rc), rc);
5019
5020 /*
5021 * Attach status driver for shared folders (optional).
5022 */
5023 PPDMIBASE pBase;
5024 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThisCC->IBase, &pBase, "Status Port");
5025 if (RT_SUCCESS(rc))
5026 pThisCC->SharedFolders.pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5027 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
5028 {
5029 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
5030 return rc;
5031 }
5032
5033 /*
5034 * Register saved state and init the HGCM CmdList critsect.
5035 */
5036 rc = PDMDevHlpSSMRegisterEx(pDevIns, VMMDEV_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
5037 NULL, vmmdevLiveExec, NULL,
5038 NULL, vmmdevSaveExec, NULL,
5039 NULL, vmmdevLoadExec, vmmdevLoadStateDone);
5040 AssertRCReturn(rc, rc);
5041
5042 /*
5043 * Create heartbeat checking timer.
5044 */
5045 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vmmDevHeartbeatFlatlinedTimer, pThis,
5046 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, "Heartbeat flatlined", &pThis->hFlatlinedTimer);
5047 AssertRCReturn(rc, rc);
5048
5049#ifdef VBOX_WITH_HGCM
5050 rc = vmmdevR3HgcmInit(pThisCC);
5051 AssertRCReturn(rc, rc);
5052#endif
5053
5054 /*
5055 * In this version of VirtualBox the GUI checks whether "needs host cursor"
5056 * changes.
5057 */
5058 pThis->fMouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
5059
5060 /*
5061 * In this version of VirtualBox full mouse state can be provided to the guest over DevVMM.
5062 */
5063 pThis->fMouseCapabilities |= VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL;
5064
5065 /*
5066 * Statistics.
5067 */
5068 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5069 "Memory balloon size", "BalloonChunks");
5070 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatFastIrqAckR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5071 "Fast IRQ acknowledgments handled in ring-3.", "FastIrqAckR3");
5072 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatFastIrqAckRZ, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5073 "Fast IRQ acknowledgments handled in ring-0 or raw-mode.", "FastIrqAckRZ");
5074 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatSlowIrqAck, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5075 "Slow IRQ acknowledgments (old style).", "SlowIrqAck");
5076 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatReqBufAllocs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5077 "Times a larger request buffer was required.", "LargeReqBufAllocs");
5078#ifdef VBOX_WITH_HGCM
5079 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmCmdArrival, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
5080 "Profiling HGCM call arrival processing", "/HGCM/MsgArrival");
5081 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmCmdCompletion, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
5082 "Profiling HGCM call completion processing", "/HGCM/MsgCompletion");
5083 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmCmdTotal, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
5084 "Profiling whole HGCM call.", "/HGCM/MsgTotal");
5085 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmLargeCmdAllocs,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5086 "Times the allocation cache could not be used.", "/HGCM/LargeCmdAllocs");
5087 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmFailedPageListLocking,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5088 "Times no-bounce page list locking failed.", "/HGCM/FailedPageListLocking");
5089#endif
5090
5091 /*
5092 * Generate a unique session id for this VM; it will be changed for each
5093 * start, reset or restore. This can be used for restore detection inside
5094 * the guest.
5095 */
5096 pThis->idSession = ASMReadTSC();
5097 return rc;
5098}
5099
5100#else /* !IN_RING3 */
5101
5102/**
5103 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5104 */
5105static DECLCALLBACK(int) vmmdevRZConstruct(PPDMDEVINS pDevIns)
5106{
5107 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5108 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
5109 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
5110
5111 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5112 AssertRCReturn(rc, rc);
5113
5114#if 0
5115 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortBackdoorLog, vmmdevBackdoorLog, NULL /*pfnIn*/, NULL /*pvUser*/);
5116 AssertRCReturn(rc, rc);
5117#endif
5118#if 0 && defined(VMMDEV_WITH_ALT_TIMESYNC)
5119 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortAltTimesync, vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead, NULL);
5120 AssertRCReturn(rc, rc);
5121#endif
5122
5123 /*
5124 * We map the first page of the VMMDevRAM into raw-mode and kernel contexts so we
5125 * can handle interrupt acknowledge requests more timely (vmmdevFastRequestIrqAck).
5126 */
5127 rc = PDMDevHlpMmio2SetUpContext(pDevIns, pThis->hMmio2VMMDevRAM, 0, GUEST_PAGE_SIZE, (void **)&pThisCC->CTX_SUFF(pVMMDevRAM));
5128 AssertRCReturn(rc, rc);
5129
5130 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortFast, vmmdevFastRequestHandler, vmmdevFastRequestIrqAck, NULL);
5131 AssertRCReturn(rc, rc);
5132
5133# ifndef VBOX_WITHOUT_TESTING_FEATURES
5134 /*
5135 * Initialize testing.
5136 */
5137 rc = vmmdevRZTestingInitialize(pDevIns);
5138 AssertRCReturn(rc, rc);
5139# endif
5140
5141 return VINF_SUCCESS;
5142}
5143
5144#endif /* !IN_RING3 */
5145
5146/**
5147 * The device registration structure.
5148 */
5149extern "C" const PDMDEVREG g_DeviceVMMDev =
5150{
5151 /* .u32Version = */ PDM_DEVREG_VERSION,
5152 /* .uReserved0 = */ 0,
5153 /* .szName = */ "VMMDev",
5154 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
5155 /* .fClass = */ PDM_DEVREG_CLASS_VMM_DEV,
5156 /* .cMaxInstances = */ 1,
5157 /* .uSharedVersion = */ 42,
5158 /* .cbInstanceShared = */ sizeof(VMMDEV),
5159 /* .cbInstanceCC = */ sizeof(VMMDEVCC),
5160 /* .cbInstanceRC = */ sizeof(VMMDEVRC),
5161 /* .cMaxPciDevices = */ 1,
5162 /* .cMaxMsixVectors = */ 0,
5163 /* .pszDescription = */ "VirtualBox VMM Device\n",
5164#if defined(IN_RING3)
5165 /* .pszRCMod = */ "VBoxDDRC.rc",
5166 /* .pszR0Mod = */ "VBoxDDR0.r0",
5167 /* .pfnConstruct = */ vmmdevConstruct,
5168 /* .pfnDestruct = */ vmmdevDestruct,
5169# ifdef VBOX_WITH_RAW_MODE_KEEP
5170 /* .pfnRelocate = */ vmmdevRelocate,
5171# else
5172 /* .pfnRelocate = */ NULL,
5173# endif
5174 /* .pfnMemSetup = */ NULL,
5175 /* .pfnPowerOn = */ NULL,
5176 /* .pfnReset = */ vmmdevReset,
5177 /* .pfnSuspend = */ NULL,
5178 /* .pfnResume = */ NULL,
5179 /* .pfnAttach = */ NULL,
5180 /* .pfnDetach = */ NULL,
5181 /* .pfnQueryInterface = */ NULL,
5182 /* .pfnInitComplete = */ NULL,
5183 /* .pfnPowerOff = */ NULL,
5184 /* .pfnSoftReset = */ NULL,
5185 /* .pfnReserved0 = */ NULL,
5186 /* .pfnReserved1 = */ NULL,
5187 /* .pfnReserved2 = */ NULL,
5188 /* .pfnReserved3 = */ NULL,
5189 /* .pfnReserved4 = */ NULL,
5190 /* .pfnReserved5 = */ NULL,
5191 /* .pfnReserved6 = */ NULL,
5192 /* .pfnReserved7 = */ NULL,
5193#elif defined(IN_RING0)
5194 /* .pfnEarlyConstruct = */ NULL,
5195 /* .pfnConstruct = */ vmmdevRZConstruct,
5196 /* .pfnDestruct = */ NULL,
5197 /* .pfnFinalDestruct = */ NULL,
5198 /* .pfnRequest = */ NULL,
5199 /* .pfnReserved0 = */ NULL,
5200 /* .pfnReserved1 = */ NULL,
5201 /* .pfnReserved2 = */ NULL,
5202 /* .pfnReserved3 = */ NULL,
5203 /* .pfnReserved4 = */ NULL,
5204 /* .pfnReserved5 = */ NULL,
5205 /* .pfnReserved6 = */ NULL,
5206 /* .pfnReserved7 = */ NULL,
5207#elif defined(IN_RC)
5208 /* .pfnConstruct = */ vmmdevRZConstruct,
5209 /* .pfnReserved0 = */ NULL,
5210 /* .pfnReserved1 = */ NULL,
5211 /* .pfnReserved2 = */ NULL,
5212 /* .pfnReserved3 = */ NULL,
5213 /* .pfnReserved4 = */ NULL,
5214 /* .pfnReserved5 = */ NULL,
5215 /* .pfnReserved6 = */ NULL,
5216 /* .pfnReserved7 = */ NULL,
5217#else
5218# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5219#endif
5220 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5221};
5222
5223#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