VirtualBox

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

Last change on this file was 106971, checked in by vboxsync, 3 weeks ago

VBox/ostypes.h+Main/{Global,Appliance}+VMMDev: Add a new OStype for Windows
Server 2025. This complements the icon changes made in r165859.

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