VirtualBox

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

Last change on this file since 107349 was 107248, checked in by vboxsync, 8 weeks ago

VBox/ostypes.h+Main/{Global,Appliance}+VMMDev+FE/Qt: Fill in some
missing ARM64 pieces from some recent incomplete updates to
Global::OSTypes[] such as the appliance import g_aOsTypes[] array and
the icon matching code in the GUI. Also add a few new Linux ARM entries
such as 'Red Hat 9.x' and 'Ubuntu 24.10'.

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

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