VirtualBox

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

Last change on this file since 100827 was 100827, checked in by vboxsync, 9 months ago

VBox/ostypes.h+Main/{Global,Appliance},VMMDev,FE/Qt: Update the Linux OS
subtypes with recent releases: Debian 12 and Ubuntu 22.10 and 23.04.
bugref:5936

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

© 2023 Oracle
ContactPrivacy policyTerms of Use