VirtualBox

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

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

Devices/VMMDev: Add an MMIO interface in addition to the existing PIO interface for guest additions running inside an ARM based guest. Also remove the dependency from the architecture page size and introduce a 4KiB VMM page size as ARM has different page sizes (4KiB, 16KiB, 64KiB) and it can differ between host and guest, bugref:10456 [build fix]

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

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