VirtualBox

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

Last change on this file since 106401 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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