VirtualBox

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

Last change on this file since 100185 was 100185, checked in by vboxsync, 18 months 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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 215.8 KB
Line 
1/* $Id: VMMDev.cpp 100185 2023-06-16 06:54:50Z vboxsync $ */
2/** @file
3 * VMMDev - Guest <-> VMM/Host communication device.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/** @page pg_vmmdev The VMM Device.
29 *
30 * The VMM device is a custom hardware device emulation for communicating with
31 * the guest additions.
32 *
33 * Whenever host wants to inform guest about something an IRQ notification will
34 * be raised.
35 *
36 * VMMDev PDM interface will contain the guest notification method.
37 *
38 * There is a 32 bit event mask which will be read by guest on an interrupt. A
39 * non zero bit in the mask means that the specific event occurred and requires
40 * processing on guest side.
41 *
42 * After reading the event mask guest must issue a generic request
43 * AcknowlegdeEvents.
44 *
45 * IRQ line is set to 1 (request) if there are unprocessed events, that is the
46 * event mask is not zero.
47 *
48 * After receiving an interrupt and checking event mask, the guest must process
49 * events using the event specific mechanism.
50 *
51 * That is if mouse capabilities were changed, guest will use
52 * VMMDev_GetMouseStatus generic request.
53 *
54 * Event mask is only a set of flags indicating that guest must proceed with a
55 * procedure.
56 *
57 * Unsupported events are therefore ignored. The guest additions must inform
58 * host which events they want to receive, to avoid unnecessary IRQ processing.
59 * By default no events are signalled to guest.
60 *
61 * This seems to be fast method. It requires only one context switch for an
62 * event processing.
63 *
64 *
65 * @section sec_vmmdev_heartbeat Heartbeat
66 *
67 * The heartbeat is a feature to monitor whether the guest OS is hung or not.
68 *
69 * The main kernel component of the guest additions, VBoxGuest, sets up a timer
70 * at a frequency returned by VMMDevReq_HeartbeatConfigure
71 * (VMMDevReqHeartbeat::cNsInterval, VMMDEV::cNsHeartbeatInterval) and performs
72 * a VMMDevReq_GuestHeartbeat request every time the timer ticks.
73 *
74 * The host side (VMMDev) arms a timer with a more distant deadline
75 * (VMMDEV::cNsHeartbeatTimeout), twice cNsHeartbeatInterval by default. Each
76 * time a VMMDevReq_GuestHeartbeat request comes in, the timer is rearmed with
77 * the same relative deadline. So, as long as VMMDevReq_GuestHeartbeat comes
78 * when they should, the host timer will never fire.
79 *
80 * When the timer fires, we consider the guest as hung / flatlined / dead.
81 * Currently we only LogRel that, but it's easy to extend this with an event in
82 * Main API.
83 *
84 * Should the guest reawaken at some later point, we LogRel that event and
85 * continue as normal. Again something which would merit an API event.
86 *
87 */
88
89
90/*********************************************************************************************************************************
91* Header Files *
92*********************************************************************************************************************************/
93/* Enable dev_vmm Log3 statements to get IRQ-related logging. */
94#define LOG_GROUP LOG_GROUP_DEV_VMM
95#include <VBox/AssertGuest.h>
96#include <VBox/VMMDev.h>
97#include <VBox/vmm/dbgf.h>
98#include <VBox/vmm/mm.h>
99#include <VBox/log.h>
100#include <VBox/param.h>
101#include <iprt/path.h>
102#include <iprt/dir.h>
103#include <iprt/file.h>
104#include <VBox/vmm/pgm.h>
105#include <VBox/err.h>
106#include <VBox/dbg.h>
107#include <VBox/version.h>
108
109#include <iprt/asm.h>
110#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
111# include <iprt/asm-amd64-x86.h> /* ASMReadTsc */
112#endif
113#include <iprt/assert.h>
114#include <iprt/buildconfig.h>
115#include <iprt/string.h>
116#include <iprt/system.h>
117#include <iprt/time.h>
118#ifndef IN_RC
119# include <iprt/mem.h>
120# include <iprt/memsafer.h>
121#endif
122#ifdef IN_RING3
123# include <iprt/uuid.h>
124#endif
125
126#include "VMMDevState.h"
127#ifdef VBOX_WITH_HGCM
128# include "VMMDevHGCM.h"
129#endif
130#ifndef VBOX_WITHOUT_TESTING_FEATURES
131# include "VMMDevTesting.h"
132#endif
133
134
135/*********************************************************************************************************************************
136* Defined Constants And Macros *
137*********************************************************************************************************************************/
138#define VMMDEV_INTERFACE_VERSION_IS_1_03(s) \
139 ( RT_HIWORD((s)->guestInfo.interfaceVersion) == 1 \
140 && RT_LOWORD((s)->guestInfo.interfaceVersion) == 3 )
141
142#define VMMDEV_INTERFACE_VERSION_IS_OK(additionsVersion) \
143 ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
144 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) )
145
146#define VMMDEV_INTERFACE_VERSION_IS_OLD(additionsVersion) \
147 ( (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
148 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
149 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) ) )
150
151#define VMMDEV_INTERFACE_VERSION_IS_TOO_OLD(additionsVersion) \
152 ( RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) )
153
154#define VMMDEV_INTERFACE_VERSION_IS_NEW(additionsVersion) \
155 ( RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
156 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
157 && RT_LOWORD(additionsVersion) > RT_LOWORD(VMMDEV_VERSION) ) )
158
159/** Default interval in nanoseconds between guest heartbeats.
160 * Used when no HeartbeatInterval is set in CFGM and for setting
161 * HB check timer if the guest's heartbeat frequency is less than 1Hz. */
162#define VMMDEV_HEARTBEAT_DEFAULT_INTERVAL (2U*RT_NS_1SEC_64)
163
164
165#ifndef VBOX_DEVICE_STRUCT_TESTCASE
166#ifdef IN_RING3
167
168/** DISPLAYCHANGEDATA field descriptors for the v18+ saved state. */
169static SSMFIELD const g_aSSMDISPLAYCHANGEDATAStateFields[] =
170{
171 SSMFIELD_ENTRY(DISPLAYCHANGEDATA, iCurrentMonitor),
172 SSMFIELD_ENTRY(DISPLAYCHANGEDATA, fGuestSentChangeEventAck),
173 SSMFIELD_ENTRY(DISPLAYCHANGEDATA, afAlignment),
174 SSMFIELD_ENTRY(DISPLAYCHANGEDATA, aRequests),
175 SSMFIELD_ENTRY_TERM()
176};
177
178/* -=-=-=-=- Misc Helpers -=-=-=-=- */
179
180/**
181 * Log information about the Guest Additions.
182 *
183 * @param pGuestInfo The information we've got from the Guest Additions driver.
184 */
185static void vmmdevLogGuestOsInfo(VBoxGuestInfo *pGuestInfo)
186{
187 const char *pszOs;
188 switch (pGuestInfo->osType & ~VBOXOSTYPE_x64)
189 {
190 case VBOXOSTYPE_DOS: pszOs = "DOS"; break;
191 case VBOXOSTYPE_Win31: pszOs = "Windows 3.1"; break;
192 case VBOXOSTYPE_Win9x: pszOs = "Windows 9x"; break;
193 case VBOXOSTYPE_Win95: pszOs = "Windows 95"; break;
194 case VBOXOSTYPE_Win98: pszOs = "Windows 98"; break;
195 case VBOXOSTYPE_WinMe: pszOs = "Windows Me"; break;
196 case VBOXOSTYPE_WinNT: pszOs = "Windows NT"; break;
197 case VBOXOSTYPE_WinNT3x: pszOs = "Windows NT 3.x"; break;
198 case VBOXOSTYPE_WinNT4: pszOs = "Windows NT4"; break;
199 case VBOXOSTYPE_Win2k: pszOs = "Windows 2k"; break;
200 case VBOXOSTYPE_WinXP: pszOs = "Windows XP"; break;
201 case VBOXOSTYPE_Win2k3: pszOs = "Windows 2k3"; break;
202 case VBOXOSTYPE_WinVista: pszOs = "Windows Vista"; break;
203 case VBOXOSTYPE_Win2k8: pszOs = "Windows 2k8"; break;
204 case VBOXOSTYPE_Win7: pszOs = "Windows 7"; break;
205 case VBOXOSTYPE_Win8: pszOs = "Windows 8"; break;
206 case VBOXOSTYPE_Win2k12_x64 & ~VBOXOSTYPE_x64: pszOs = "Windows 2k12"; break;
207 case VBOXOSTYPE_Win81: pszOs = "Windows 8.1"; break;
208 case VBOXOSTYPE_Win10: pszOs = "Windows 10"; break;
209 case VBOXOSTYPE_Win2k16_x64 & ~VBOXOSTYPE_x64: pszOs = "Windows 2k16"; break;
210 case VBOXOSTYPE_Win2k19_x64 & ~VBOXOSTYPE_x64: pszOs = "Windows 2k19"; break;
211 case VBOXOSTYPE_Win11_x64 & ~VBOXOSTYPE_x64: pszOs = "Windows 11"; break;
212 case VBOXOSTYPE_OS2: pszOs = "OS/2"; break;
213 case VBOXOSTYPE_OS2Warp3: pszOs = "OS/2 Warp 3"; break;
214 case VBOXOSTYPE_OS2Warp4: pszOs = "OS/2 Warp 4"; break;
215 case VBOXOSTYPE_OS2Warp45: pszOs = "OS/2 Warp 4.5"; break;
216 case VBOXOSTYPE_ECS: pszOs = "OS/2 ECS"; break;
217 case VBOXOSTYPE_ArcaOS: pszOs = "OS/2 ArcaOS"; break;
218 case VBOXOSTYPE_OS21x: pszOs = "OS/2 2.1x"; break;
219 case VBOXOSTYPE_Linux: pszOs = "Linux"; break;
220 case VBOXOSTYPE_Linux22: pszOs = "Linux 2.2"; break;
221 case VBOXOSTYPE_Linux24: pszOs = "Linux 2.4"; break;
222 case VBOXOSTYPE_Linux26: pszOs = "Linux >= 2.6"; break;
223 case VBOXOSTYPE_ArchLinux: pszOs = "ArchLinux"; break;
224 case VBOXOSTYPE_Debian: pszOs = "Debian"; break;
225 case VBOXOSTYPE_Debian31: pszOs = "Debian 3.1"; break;
226 case VBOXOSTYPE_Debian4: pszOs = "Debian 4.0"; break;
227 case VBOXOSTYPE_Debian5: pszOs = "Debian 5.0"; break;
228 case VBOXOSTYPE_Debian6: pszOs = "Debian 6.0"; break;
229 case VBOXOSTYPE_Debian7: pszOs = "Debian 7"; break;
230 case VBOXOSTYPE_Debian8: pszOs = "Debian 8"; break;
231 case VBOXOSTYPE_Debian9: pszOs = "Debian 9"; break;
232 case VBOXOSTYPE_Debian10: pszOs = "Debian 10"; break;
233 case VBOXOSTYPE_Debian11: pszOs = "Debian 11"; break;
234 case VBOXOSTYPE_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 rcStrict = vmmdevRequestHandler(pDevIns, u64Val);
3498 break;
3499 case VMMDEV_MMIO_OFF_REQUEST_FAST:
3500#ifndef IN_RING3
3501 rcStrict = VINF_IOM_R3_MMIO_WRITE;
3502#else
3503 rcStrict = vmmdevRequestHandler(pDevIns, u64Val);
3504#endif
3505 break;
3506 default:
3507 /* Ignore writes to unimplemented or read-only registers. */
3508 Log(("VMMDev: Trying to write unimplemented or R/O register at offset %04X!\n", offReg));
3509 rcStrict = VINF_SUCCESS;
3510 break;
3511 }
3512
3513 return rcStrict;
3514}
3515
3516
3517
3518#ifdef IN_RING3
3519
3520/* -=-=-=-=-=- PCI Device -=-=-=-=-=- */
3521
3522/**
3523 * @callback_method_impl{FNPCIIOREGIONMAP,I/O Port Region}
3524 */
3525static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
3526 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
3527{
3528 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3529 LogFlow(("vmmdevIOPortRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
3530 RT_NOREF(pPciDev, iRegion, cb, enmType);
3531
3532 Assert(pPciDev == pDevIns->apPciDevs[0]);
3533 Assert(enmType == PCI_ADDRESS_SPACE_IO);
3534 Assert(iRegion == 0);
3535
3536 int rc;
3537 if (GCPhysAddress != NIL_RTGCPHYS)
3538 {
3539 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#RGp\n", GCPhysAddress));
3540
3541 rc = PDMDevHlpIoPortMap(pDevIns, pThis->hIoPortReq, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST);
3542 AssertLogRelRCReturn(rc, rc);
3543
3544 rc = PDMDevHlpIoPortMap(pDevIns, pThis->hIoPortFast, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST_FAST);
3545 AssertLogRelRCReturn(rc, rc);
3546 }
3547 else
3548 {
3549 rc = PDMDevHlpIoPortUnmap(pDevIns, pThis->hIoPortReq);
3550 AssertLogRelRCReturn(rc, rc);
3551
3552 rc = PDMDevHlpIoPortUnmap(pDevIns, pThis->hIoPortFast);
3553 AssertLogRelRCReturn(rc, rc);
3554 }
3555 return rc;
3556}
3557
3558
3559/**
3560 * @callback_method_impl{FNPCIIOREGIONMAP,VMMDev heap (MMIO2)}
3561 */
3562static DECLCALLBACK(int) vmmdevMmio2HeapRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
3563 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
3564{
3565 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
3566 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
3567 RT_NOREF(cb, pPciDev);
3568
3569 Assert(pPciDev == pDevIns->apPciDevs[0]);
3570 AssertReturn(iRegion == 2, VERR_INTERNAL_ERROR_2);
3571 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR_3);
3572 Assert(pThisCC->pVMMDevHeapR3 != NULL);
3573
3574 int rc;
3575 if (GCPhysAddress != NIL_RTGCPHYS)
3576 {
3577 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, GCPhysAddress, pThisCC->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
3578 AssertRC(rc);
3579 }
3580 else
3581 {
3582 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThisCC->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
3583 AssertRCStmt(rc, rc = VINF_SUCCESS);
3584 }
3585
3586 return rc;
3587}
3588
3589
3590/* -=-=-=-=-=- Backdoor Logging and Time Sync. -=-=-=-=-=- */
3591
3592/**
3593 * @callback_method_impl{FNIOMIOPORTNEWOUT, Backdoor Logging.}
3594 */
3595static DECLCALLBACK(VBOXSTRICTRC)
3596vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3597{
3598 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3599 RT_NOREF(pvUser, offPort);
3600 Assert(offPort == 0);
3601
3602 if (!pThis->fBackdoorLogDisabled && cb == 1)
3603 {
3604
3605 /* The raw version. */
3606 switch (u32)
3607 {
3608 case '\r': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
3609 case '\n': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
3610 case '\t': LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
3611 default: LogIt(RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: %c (%02x)\n", u32, u32)); break;
3612 }
3613
3614 /* The readable, buffered version. */
3615 uint32_t offMsg = RT_MIN(pThis->offMsg, sizeof(pThis->szMsg) - 1);
3616 if (u32 == '\n' || u32 == '\r')
3617 {
3618 pThis->szMsg[offMsg] = '\0';
3619 if (offMsg)
3620 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("VMMDev: Guest Log: %.*s\n", offMsg, pThis->szMsg));
3621 pThis->offMsg = 0;
3622 }
3623 else
3624 {
3625 if (offMsg >= sizeof(pThis->szMsg) - 1)
3626 {
3627 pThis->szMsg[sizeof(pThis->szMsg) - 1] = '\0';
3628 LogRelIt(RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR,
3629 ("VMMDev: Guest Log: %.*s\n", sizeof(pThis->szMsg) - 1, pThis->szMsg));
3630 offMsg = 0;
3631 }
3632 pThis->szMsg[offMsg++] = (char )u32;
3633 pThis->szMsg[offMsg] = '\0';
3634 pThis->offMsg = offMsg;
3635 }
3636 }
3637 return VINF_SUCCESS;
3638}
3639
3640#ifdef VMMDEV_WITH_ALT_TIMESYNC
3641
3642/**
3643 * @callback_method_impl{FNIOMIOPORTNEWOUT, Alternative time synchronization.}
3644 */
3645static DECLCALLBACK(VBOXSTRICTRC)
3646vmmdevAltTimeSyncWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3647{
3648 RT_NOREF(pvUser, offPort);
3649 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3650 if (cb == 4)
3651 {
3652 /* Selects high (0) or low (1) DWORD. The high has to be read first. */
3653 switch (u32)
3654 {
3655 case 0:
3656 pThis->fTimesyncBackdoorLo = false;
3657 break;
3658 case 1:
3659 pThis->fTimesyncBackdoorLo = true;
3660 break;
3661 default:
3662 Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
3663 break;
3664 }
3665 }
3666 else
3667 Log(("vmmdevAltTimeSyncWrite: Invalid access cb=%#x u32=%#x\n", cb, u32));
3668 return VINF_SUCCESS;
3669}
3670
3671/**
3672 * @callback_method_impl{FNIOMIOPORTOUT, Alternative time synchronization.}
3673 */
3674static DECLCALLBACK(VBOXSTRICTRC)
3675vmmdevAltTimeSyncRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
3676{
3677 RT_NOREF(pvUser, offPort);
3678 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3679 VBOXSTRICTRC rc;
3680 if (cb == 4)
3681 {
3682 if (pThis->fTimesyncBackdoorLo)
3683 *pu32 = (uint32_t)pThis->msLatchedHostTime;
3684 else
3685 {
3686 /* Reading the high dword gets and saves the current time. */
3687 RTTIMESPEC Now;
3688 pThis->msLatchedHostTime = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &Now));
3689 *pu32 = (uint32_t)(pThis->msLatchedHostTime >> 32);
3690 }
3691 rc = VINF_SUCCESS;
3692 }
3693 else
3694 {
3695 Log(("vmmdevAltTimeSyncRead: Invalid access cb=%#x\n", cb));
3696 rc = VERR_IOM_IOPORT_UNUSED;
3697 }
3698 return rc;
3699}
3700
3701#endif /* VMMDEV_WITH_ALT_TIMESYNC */
3702
3703
3704/* -=-=-=-=-=- IBase -=-=-=-=-=- */
3705
3706/**
3707 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3708 */
3709static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3710{
3711 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IBase);
3712
3713 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
3714 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThisCC->IPort);
3715#ifdef VBOX_WITH_HGCM
3716 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMPORT, &pThisCC->IHGCMPort);
3717#endif
3718 /* Currently only for shared folders. */
3719 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->SharedFolders.ILeds);
3720 return NULL;
3721}
3722
3723
3724/* -=-=-=-=-=- ILeds -=-=-=-=-=- */
3725
3726/**
3727 * Gets the pointer to the status LED of a unit.
3728 *
3729 * @returns VBox status code.
3730 * @param pInterface Pointer to the interface structure containing the called function pointer.
3731 * @param iLUN The unit which status LED we desire.
3732 * @param ppLed Where to store the LED pointer.
3733 */
3734static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
3735{
3736 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, SharedFolders.ILeds);
3737 if (iLUN == 0) /* LUN 0 is shared folders */
3738 {
3739 *ppLed = &pThisCC->SharedFolders.Led;
3740 return VINF_SUCCESS;
3741 }
3742 return VERR_PDM_LUN_NOT_FOUND;
3743}
3744
3745
3746/* -=-=-=-=-=- PDMIVMMDEVPORT (VMMDEV::IPort) -=-=-=-=-=- */
3747
3748/**
3749 * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryAbsoluteMouse}
3750 */
3751static DECLCALLBACK(int) vmmdevIPort_QueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)
3752{
3753 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3754 PVMMDEV pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVMMDEV);
3755
3756 /** @todo at the first sign of trouble in this area, just enter the critsect.
3757 * As indicated by the comment below, the atomic reads serves no real purpose
3758 * here since we can assume cache coherency protocoles and int32_t alignment
3759 * rules making sure we won't see a halfwritten value. */
3760 if (pxAbs)
3761 *pxAbs = ASMAtomicReadS32(&pThis->xMouseAbs); /* why the atomic read? */
3762 if (pyAbs)
3763 *pyAbs = ASMAtomicReadS32(&pThis->yMouseAbs);
3764
3765 return VINF_SUCCESS;
3766}
3767
3768/**
3769 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetAbsoluteMouse}
3770 */
3771static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs,
3772 int32_t dz, int32_t dw, uint32_t fButtons)
3773{
3774 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3775 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3776 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3777 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3778 AssertRCReturn(rcLock, rcLock);
3779
3780 if ( pThis->xMouseAbs != xAbs
3781 || pThis->yMouseAbs != yAbs
3782 || dz
3783 || dw
3784 || pThis->fMouseButtons != fButtons)
3785 {
3786 Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d, z = %d, w = %d, fButtons = 0x%x\n",
3787 xAbs, yAbs, dz, dw, fButtons));
3788
3789 pThis->xMouseAbs = xAbs;
3790 pThis->yMouseAbs = yAbs;
3791 pThis->dzMouse = dz;
3792 pThis->dwMouse = dw;
3793 pThis->fMouseButtons = fButtons;
3794
3795 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
3796 }
3797
3798 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3799 return VINF_SUCCESS;
3800}
3801
3802/**
3803 * @interface_method_impl{PDMIVMMDEVPORT,pfnQueryMouseCapabilities}
3804 */
3805static DECLCALLBACK(int) vmmdevIPort_QueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)
3806{
3807 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3808 PVMMDEV pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVMMDEV);
3809 AssertPtrReturn(pfCapabilities, VERR_INVALID_PARAMETER);
3810
3811 *pfCapabilities = pThis->fMouseCapabilities;
3812 return VINF_SUCCESS;
3813}
3814
3815/**
3816 * @interface_method_impl{PDMIVMMDEVPORT,pfnUpdateMouseCapabilities}
3817 */
3818static DECLCALLBACK(int)
3819vmmdevIPort_UpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)
3820{
3821 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3822 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3823 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3824 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3825 AssertRCReturn(rcLock, rcLock);
3826
3827 uint32_t fOldCaps = pThis->fMouseCapabilities;
3828 pThis->fMouseCapabilities &= ~(fCapsRemoved & VMMDEV_MOUSE_HOST_MASK);
3829 pThis->fMouseCapabilities |= (fCapsAdded & VMMDEV_MOUSE_HOST_MASK)
3830 | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR
3831 | VMMDEV_MOUSE_HOST_SUPPORTS_FULL_STATE_PROTOCOL;
3832 bool fNotify = fOldCaps != pThis->fMouseCapabilities;
3833
3834 LogRelFlow(("VMMDev: vmmdevIPort_UpdateMouseCapabilities: fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify=%RTbool\n", fCapsAdded,
3835 fCapsRemoved, fNotify));
3836
3837 if (fNotify)
3838 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
3839
3840 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3841 return VINF_SUCCESS;
3842}
3843
3844static bool vmmdevIsMonitorDefEqual(VMMDevDisplayDef const *pNew, VMMDevDisplayDef const *pOld)
3845{
3846 bool fEqual = pNew->idDisplay == pOld->idDisplay;
3847
3848 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN) /* No change. */
3849 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN) /* Old value exists and */
3850 && pNew->xOrigin == pOld->xOrigin /* the old is equal to the new. */
3851 && pNew->yOrigin == pOld->yOrigin));
3852
3853 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_CX)
3854 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_CX)
3855 && pNew->cx == pOld->cx));
3856
3857 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_CY)
3858 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_CY)
3859 && pNew->cy == pOld->cy));
3860
3861 fEqual = fEqual && ( !RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_BPP)
3862 || ( RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_BPP)
3863 && pNew->cBitsPerPixel == pOld->cBitsPerPixel));
3864
3865 fEqual = fEqual && ( RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_DISABLED)
3866 == RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_DISABLED));
3867
3868 fEqual = fEqual && ( RT_BOOL(pNew->fDisplayFlags & VMMDEV_DISPLAY_PRIMARY)
3869 == RT_BOOL(pOld->fDisplayFlags & VMMDEV_DISPLAY_PRIMARY));
3870
3871 return fEqual;
3872}
3873
3874/**
3875 * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestDisplayChange}
3876 */
3877static DECLCALLBACK(int)
3878vmmdevIPort_RequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t cDisplays, VMMDevDisplayDef const *paDisplays, bool fForce, bool fMayNotify)
3879{
3880 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3881 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3882 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3883 int rc = VINF_SUCCESS;
3884 bool fNotifyGuest = false;
3885 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3886 AssertRCReturn(rcLock, rcLock);
3887
3888 uint32_t i;
3889 for (i = 0; i < cDisplays; ++i)
3890 {
3891 VMMDevDisplayDef const *p = &paDisplays[i];
3892
3893 /* Either one display definition is provided or the display id must be equal to the array index. */
3894 AssertBreakStmt(cDisplays == 1 || p->idDisplay == i, rc = VERR_INVALID_PARAMETER);
3895 AssertBreakStmt(p->idDisplay < RT_ELEMENTS(pThis->displayChangeData.aRequests), rc = VERR_INVALID_PARAMETER);
3896
3897 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[p->idDisplay];
3898
3899 VMMDevDisplayDef const *pLastRead = &pRequest->lastReadDisplayChangeRequest;
3900
3901 /* Verify that the new resolution is different and that guest does not yet know about it. */
3902 bool const fDifferentResolution = fForce || !vmmdevIsMonitorDefEqual(p, pLastRead);
3903
3904 LogFunc(("same=%d. New: %dx%d, cBits=%d, id=%d. Old: %dx%d, cBits=%d, id=%d. @%d,%d, Enabled=%d, ChangeOrigin=%d\n",
3905 !fDifferentResolution, p->cx, p->cy, p->cBitsPerPixel, p->idDisplay,
3906 pLastRead->cx, pLastRead->cy, pLastRead->cBitsPerPixel, pLastRead->idDisplay,
3907 p->xOrigin, p->yOrigin,
3908 !RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_DISABLED),
3909 RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN)));
3910
3911 /* We could validate the information here but hey, the guest can do that as well! */
3912 pRequest->displayChangeRequest = *p;
3913 pRequest->fPending = fDifferentResolution && fMayNotify;
3914
3915 fNotifyGuest = fNotifyGuest || fDifferentResolution;
3916 }
3917
3918 if (RT_SUCCESS(rc) && fMayNotify)
3919 {
3920 if (fNotifyGuest)
3921 {
3922 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); ++i)
3923 {
3924 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
3925 if (pRequest->fPending)
3926 {
3927 VMMDevDisplayDef const *p = &pRequest->displayChangeRequest;
3928 LogRel(("VMMDev: SetVideoModeHint: Got a video mode hint (%dx%dx%d)@(%dx%d),(%d;%d) at %d\n",
3929 p->cx, p->cy, p->cBitsPerPixel, p->xOrigin, p->yOrigin,
3930 !RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_DISABLED),
3931 RT_BOOL(p->fDisplayFlags & VMMDEV_DISPLAY_ORIGIN), i));
3932 }
3933 }
3934
3935 /* IRQ so the guest knows what's going on */
3936 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
3937 }
3938 }
3939
3940 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3941 return rc;
3942}
3943
3944/**
3945 * @interface_method_impl{PDMIVMMDEVPORT,pfnRequestSeamlessChange}
3946 */
3947static DECLCALLBACK(int) vmmdevIPort_RequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
3948{
3949 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3950 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3951 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3952 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3953 AssertRCReturn(rcLock, rcLock);
3954
3955 /* Verify that the new resolution is different and that guest does not yet know about it. */
3956 bool fSameMode = (pThis->fLastSeamlessEnabled == fEnabled);
3957
3958 Log(("vmmdevIPort_RequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
3959
3960 if (!fSameMode)
3961 {
3962 /* we could validate the information here but hey, the guest can do that as well! */
3963 pThis->fSeamlessEnabled = fEnabled;
3964
3965 /* IRQ so the guest knows what's going on */
3966 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
3967 }
3968
3969 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3970 return VINF_SUCCESS;
3971}
3972
3973/**
3974 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetMemoryBalloon}
3975 */
3976static DECLCALLBACK(int) vmmdevIPort_SetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)
3977{
3978 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
3979 PPDMDEVINS pDevIns = pThisCC->pDevIns;
3980 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
3981 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
3982 AssertRCReturn(rcLock, rcLock);
3983
3984 /* Verify that the new resolution is different and that guest does not yet know about it. */
3985 Log(("vmmdevIPort_SetMemoryBalloon: old=%u new=%u\n", pThis->cMbMemoryBalloonLast, cMbBalloon));
3986 if (pThis->cMbMemoryBalloonLast != cMbBalloon)
3987 {
3988 /* we could validate the information here but hey, the guest can do that as well! */
3989 pThis->cMbMemoryBalloon = cMbBalloon;
3990
3991 /* IRQ so the guest knows what's going on */
3992 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
3993 }
3994
3995 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3996 return VINF_SUCCESS;
3997}
3998
3999/**
4000 * @interface_method_impl{PDMIVMMDEVPORT,pfnVRDPChange}
4001 */
4002static DECLCALLBACK(int) vmmdevIPort_VRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)
4003{
4004 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4005 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4006 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4007 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4008 AssertRCReturn(rcLock, rcLock);
4009
4010 bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
4011
4012 Log(("vmmdevIPort_VRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
4013
4014 if (!fSame)
4015 {
4016 pThis->fVRDPEnabled = fVRDPEnabled;
4017 pThis->uVRDPExperienceLevel = uVRDPExperienceLevel;
4018
4019 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_VRDP);
4020 }
4021
4022 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4023 return VINF_SUCCESS;
4024}
4025
4026/**
4027 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetStatisticsInterval}
4028 */
4029static DECLCALLBACK(int) vmmdevIPort_SetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)
4030{
4031 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4032 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4033 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4034 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4035 AssertRCReturn(rcLock, rcLock);
4036
4037 /* Verify that the new resolution is different and that guest does not yet know about it. */
4038 bool fSame = (pThis->cSecsLastStatInterval == cSecsStatInterval);
4039
4040 Log(("vmmdevIPort_SetStatisticsInterval: old=%d. new=%d\n", pThis->cSecsLastStatInterval, cSecsStatInterval));
4041
4042 if (!fSame)
4043 {
4044 /* we could validate the information here but hey, the guest can do that as well! */
4045 pThis->cSecsStatInterval = cSecsStatInterval;
4046
4047 /* IRQ so the guest knows what's going on */
4048 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
4049 }
4050
4051 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4052 return VINF_SUCCESS;
4053}
4054
4055/**
4056 * @interface_method_impl{PDMIVMMDEVPORT,pfnSetCredentials}
4057 */
4058static DECLCALLBACK(int) vmmdevIPort_SetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
4059 const char *pszPassword, const char *pszDomain, uint32_t fFlags)
4060{
4061 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4062 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4063 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4064
4065 AssertReturn(fFlags & (VMMDEV_SETCREDENTIALS_GUESTLOGON | VMMDEV_SETCREDENTIALS_JUDGE), VERR_INVALID_PARAMETER);
4066 size_t const cchUsername = strlen(pszUsername);
4067 AssertReturn(cchUsername < VMMDEV_CREDENTIALS_SZ_SIZE, VERR_BUFFER_OVERFLOW);
4068 size_t const cchPassword = strlen(pszPassword);
4069 AssertReturn(cchPassword < VMMDEV_CREDENTIALS_SZ_SIZE, VERR_BUFFER_OVERFLOW);
4070 size_t const cchDomain = strlen(pszDomain);
4071 AssertReturn(cchDomain < VMMDEV_CREDENTIALS_SZ_SIZE, VERR_BUFFER_OVERFLOW);
4072
4073 VMMDEVCREDS *pCredentials = pThisCC->pCredentials;
4074 AssertPtrReturn(pCredentials, VERR_NOT_SUPPORTED);
4075
4076 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4077 AssertRCReturn(rcLock, rcLock);
4078
4079 /*
4080 * Logon mode
4081 */
4082 if (fFlags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
4083 {
4084 /* memorize the data */
4085 memcpy(pCredentials->Logon.szUserName, pszUsername, cchUsername);
4086 pThisCC->pCredentials->Logon.szUserName[cchUsername] = '\0';
4087 memcpy(pCredentials->Logon.szPassword, pszPassword, cchPassword);
4088 pCredentials->Logon.szPassword[cchPassword] = '\0';
4089 memcpy(pCredentials->Logon.szDomain, pszDomain, cchDomain);
4090 pCredentials->Logon.szDomain[cchDomain] = '\0';
4091 pCredentials->Logon.fAllowInteractiveLogon = !(fFlags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
4092 }
4093 /*
4094 * Credentials verification mode?
4095 */
4096 else
4097 {
4098 /* memorize the data */
4099 memcpy(pCredentials->Judge.szUserName, pszUsername, cchUsername);
4100 pCredentials->Judge.szUserName[cchUsername] = '\0';
4101 memcpy(pCredentials->Judge.szPassword, pszPassword, cchPassword);
4102 pCredentials->Judge.szPassword[cchPassword] = '\0';
4103 memcpy(pCredentials->Judge.szDomain, pszDomain, cchDomain);
4104 pCredentials->Judge.szDomain[cchDomain] = '\0';
4105
4106 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_JUDGE_CREDENTIALS);
4107 }
4108
4109 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4110 return VINF_SUCCESS;
4111}
4112
4113/**
4114 * @interface_method_impl{PDMIVMMDEVPORT,pfnVBVAChange}
4115 *
4116 * Notification from the Display. Especially useful when acceleration is
4117 * disabled after a video mode change.
4118 */
4119static DECLCALLBACK(void) vmmdevIPort_VBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
4120{
4121 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4122 PVMMDEV pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVMMDEV);
4123 Log(("vmmdevIPort_VBVAChange: fEnabled = %d\n", fEnabled));
4124
4125 /* Only used by saved state, which I guess is why we don't bother with locking here. */
4126 pThis->u32VideoAccelEnabled = fEnabled;
4127}
4128
4129/**
4130 * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotUnplug}
4131 */
4132static DECLCALLBACK(int) vmmdevIPort_CpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
4133{
4134 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4135 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4136 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4137
4138 Log(("vmmdevIPort_CpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
4139
4140 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4141 AssertRCReturn(rc, rc);
4142
4143 if (pThis->fCpuHotPlugEventsEnabled)
4144 {
4145 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
4146 pThis->idCpuCore = idCpuCore;
4147 pThis->idCpuPackage = idCpuPackage;
4148 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_CPU_HOTPLUG);
4149 }
4150 else
4151 rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
4152
4153 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4154 return rc;
4155}
4156
4157/**
4158 * @interface_method_impl{PDMIVMMDEVPORT,pfnCpuHotPlug}
4159 */
4160static DECLCALLBACK(int) vmmdevIPort_CpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
4161{
4162 PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
4163 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4164 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4165
4166 Log(("vmmdevCpuPlug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
4167
4168 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4169 AssertRCReturn(rc, rc);
4170
4171 if (pThis->fCpuHotPlugEventsEnabled)
4172 {
4173 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Plug;
4174 pThis->idCpuCore = idCpuCore;
4175 pThis->idCpuPackage = idCpuPackage;
4176 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_CPU_HOTPLUG);
4177 }
4178 else
4179 rc = VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
4180
4181 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4182 return rc;
4183}
4184
4185
4186/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
4187
4188/**
4189 * @callback_method_impl{FNSSMDEVLIVEEXEC}
4190 */
4191static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4192{
4193 RT_NOREF(uPass);
4194 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4195 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4196
4197 pHlp->pfnSSMPutBool(pSSM, pThis->fGetHostTimeDisabled);
4198 pHlp->pfnSSMPutBool(pSSM, pThis->fBackdoorLogDisabled);
4199 pHlp->pfnSSMPutBool(pSSM, pThis->fKeepCredentials);
4200 pHlp->pfnSSMPutBool(pSSM, pThis->fHeapEnabled);
4201 pHlp->pfnSSMPutBool(pSSM, pThis->fMmioReq);
4202
4203 return VINF_SSM_DONT_CALL_AGAIN;
4204}
4205
4206
4207/**
4208 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4209 */
4210static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4211{
4212 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4213 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4214 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4215 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4216 AssertRCReturn(rc, rc);
4217
4218 vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
4219
4220 pHlp->pfnSSMPutU32(pSSM, 0 /*was pThis->hypervisorSize, which was always zero*/);
4221 pHlp->pfnSSMPutU32(pSSM, pThis->fMouseCapabilities);
4222 pHlp->pfnSSMPutS32(pSSM, pThis->xMouseAbs);
4223 pHlp->pfnSSMPutS32(pSSM, pThis->yMouseAbs);
4224 pHlp->pfnSSMPutS32(pSSM, pThis->dzMouse);
4225 pHlp->pfnSSMPutS32(pSSM, pThis->dwMouse);
4226 pHlp->pfnSSMPutU32(pSSM, pThis->fMouseButtons);
4227
4228 pHlp->pfnSSMPutBool(pSSM, pThis->fNewGuestFilterMaskValid);
4229 pHlp->pfnSSMPutU32(pSSM, pThis->fNewGuestFilterMask);
4230 pHlp->pfnSSMPutU32(pSSM, pThis->fGuestFilterMask);
4231 pHlp->pfnSSMPutU32(pSSM, pThis->fHostEventFlags);
4232 /* The following is not strictly necessary as PGM restores MMIO2, keeping it for historical reasons. */
4233 pHlp->pfnSSMPutMem(pSSM, &pThisCC->pVMMDevRAMR3->V, sizeof(pThisCC->pVMMDevRAMR3->V));
4234
4235 pHlp->pfnSSMPutMem(pSSM, &pThis->guestInfo, sizeof(pThis->guestInfo));
4236 pHlp->pfnSSMPutU32(pSSM, pThis->fu32AdditionsOk);
4237 pHlp->pfnSSMPutU32(pSSM, pThis->u32VideoAccelEnabled);
4238 pHlp->pfnSSMPutBool(pSSM, pThis->displayChangeData.fGuestSentChangeEventAck);
4239
4240 pHlp->pfnSSMPutU32(pSSM, pThis->fGuestCaps);
4241
4242#ifdef VBOX_WITH_HGCM
4243 vmmdevR3HgcmSaveState(pThisCC, pSSM);
4244#endif /* VBOX_WITH_HGCM */
4245
4246 pHlp->pfnSSMPutU32(pSSM, pThis->fHostCursorRequested);
4247
4248 pHlp->pfnSSMPutU32(pSSM, pThis->guestInfo2.uFullVersion);
4249 pHlp->pfnSSMPutU32(pSSM, pThis->guestInfo2.uRevision);
4250 pHlp->pfnSSMPutU32(pSSM, pThis->guestInfo2.fFeatures);
4251 pHlp->pfnSSMPutStrZ(pSSM, pThis->guestInfo2.szName);
4252 pHlp->pfnSSMPutU32(pSSM, pThis->cFacilityStatuses);
4253 for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++)
4254 {
4255 pHlp->pfnSSMPutU32(pSSM, pThis->aFacilityStatuses[i].enmFacility);
4256 pHlp->pfnSSMPutU32(pSSM, pThis->aFacilityStatuses[i].fFlags);
4257 pHlp->pfnSSMPutU16(pSSM, (uint16_t)pThis->aFacilityStatuses[i].enmStatus);
4258 pHlp->pfnSSMPutS64(pSSM, RTTimeSpecGetNano(&pThis->aFacilityStatuses[i].TimeSpecTS));
4259 }
4260
4261 /* Heartbeat: */
4262 pHlp->pfnSSMPutBool(pSSM, pThis->fHeartbeatActive);
4263 pHlp->pfnSSMPutBool(pSSM, pThis->fFlatlined);
4264 pHlp->pfnSSMPutU64(pSSM, pThis->nsLastHeartbeatTS);
4265 PDMDevHlpTimerSave(pDevIns, pThis->hFlatlinedTimer, pSSM);
4266
4267 pHlp->pfnSSMPutStructEx(pSSM, &pThis->displayChangeData, sizeof(pThis->displayChangeData), 0,
4268 g_aSSMDISPLAYCHANGEDATAStateFields, NULL);
4269
4270 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4271 return VINF_SUCCESS;
4272}
4273
4274/**
4275 * @callback_method_impl{FNSSMDEVLOADEXEC}
4276 */
4277static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4278{
4279 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4280 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4281 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4282 int rc;
4283
4284 if ( uVersion > VMMDEV_SAVED_STATE_VERSION
4285 || uVersion < 6)
4286 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4287
4288 /* config */
4289 if (uVersion > VMMDEV_SAVED_STATE_VERSION_VBOX_30)
4290 {
4291 bool f;
4292 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4293 if (pThis->fGetHostTimeDisabled != f)
4294 LogRel(("VMMDev: Config mismatch - fGetHostTimeDisabled: config=%RTbool saved=%RTbool\n", pThis->fGetHostTimeDisabled, f));
4295
4296 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4297 if (pThis->fBackdoorLogDisabled != f)
4298 LogRel(("VMMDev: Config mismatch - fBackdoorLogDisabled: config=%RTbool saved=%RTbool\n", pThis->fBackdoorLogDisabled, f));
4299
4300 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4301 if (pThis->fKeepCredentials != f)
4302 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fKeepCredentials: config=%RTbool saved=%RTbool"),
4303 pThis->fKeepCredentials, f);
4304 rc = pHlp->pfnSSMGetBool(pSSM, &f); AssertRCReturn(rc, rc);
4305 if (pThis->fHeapEnabled != f)
4306 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fHeapEnabled: config=%RTbool saved=%RTbool"),
4307 pThis->fHeapEnabled, f);
4308
4309 f = false;
4310 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_MMIO_ACCESS)
4311 {
4312 rc = pHlp->pfnSSMGetBool(pSSM, &f);
4313 AssertRCReturn(rc, rc);
4314 }
4315 if (pThis->fMmioReq != f)
4316 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fMmioReq: config=%RTbool saved=%RTbool"),
4317 pThis->fMmioReq, f);
4318 }
4319
4320 if (uPass != SSM_PASS_FINAL)
4321 return VINF_SUCCESS;
4322
4323 /* state */
4324 uint32_t uIgn;
4325 pHlp->pfnSSMGetU32(pSSM, &uIgn);
4326 pHlp->pfnSSMGetU32(pSSM, &pThis->fMouseCapabilities);
4327 pHlp->pfnSSMGetS32(pSSM, &pThis->xMouseAbs);
4328 pHlp->pfnSSMGetS32(pSSM, &pThis->yMouseAbs);
4329 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_VMM_MOUSE_EXTENDED_DATA)
4330 {
4331 pHlp->pfnSSMGetS32(pSSM, &pThis->dzMouse);
4332 pHlp->pfnSSMGetS32(pSSM, &pThis->dwMouse);
4333 pHlp->pfnSSMGetU32(pSSM, &pThis->fMouseButtons);
4334 }
4335
4336 pHlp->pfnSSMGetBool(pSSM, &pThis->fNewGuestFilterMaskValid);
4337 pHlp->pfnSSMGetU32(pSSM, &pThis->fNewGuestFilterMask);
4338 pHlp->pfnSSMGetU32(pSSM, &pThis->fGuestFilterMask);
4339 pHlp->pfnSSMGetU32(pSSM, &pThis->fHostEventFlags);
4340
4341 //pHlp->pfnSSMGetBool(pSSM, &pThis->pVMMDevRAMR3->fHaveEvents);
4342 // here be dragons (probably)
4343 pHlp->pfnSSMGetMem(pSSM, &pThisCC->pVMMDevRAMR3->V, sizeof(pThisCC->pVMMDevRAMR3->V));
4344
4345 pHlp->pfnSSMGetMem(pSSM, &pThis->guestInfo, sizeof(pThis->guestInfo));
4346 pHlp->pfnSSMGetU32(pSSM, &pThis->fu32AdditionsOk);
4347 pHlp->pfnSSMGetU32(pSSM, &pThis->u32VideoAccelEnabled);
4348 if (uVersion > 10)
4349 pHlp->pfnSSMGetBool(pSSM, &pThis->displayChangeData.fGuestSentChangeEventAck);
4350
4351 rc = pHlp->pfnSSMGetU32(pSSM, &pThis->fGuestCaps);
4352
4353 /* Attributes which were temporarily introduced in r30072 */
4354 if (uVersion == 7)
4355 {
4356 uint32_t temp;
4357 pHlp->pfnSSMGetU32(pSSM, &temp);
4358 rc = pHlp->pfnSSMGetU32(pSSM, &temp);
4359 }
4360 AssertRCReturn(rc, rc);
4361
4362#ifdef VBOX_WITH_HGCM
4363 rc = vmmdevR3HgcmLoadState(pDevIns, pThis, pThisCC, pSSM, uVersion);
4364 AssertRCReturn(rc, rc);
4365#endif /* VBOX_WITH_HGCM */
4366
4367 if (uVersion >= 10)
4368 rc = pHlp->pfnSSMGetU32(pSSM, &pThis->fHostCursorRequested);
4369 AssertRCReturn(rc, rc);
4370
4371 if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_GUEST_INFO_2)
4372 {
4373 pHlp->pfnSSMGetU32(pSSM, &pThis->guestInfo2.uFullVersion);
4374 pHlp->pfnSSMGetU32(pSSM, &pThis->guestInfo2.uRevision);
4375 pHlp->pfnSSMGetU32(pSSM, &pThis->guestInfo2.fFeatures);
4376 rc = pHlp->pfnSSMGetStrZ(pSSM, &pThis->guestInfo2.szName[0], sizeof(pThis->guestInfo2.szName));
4377 AssertRCReturn(rc, rc);
4378 }
4379
4380 if (uVersion > VMMDEV_SAVED_STATE_VERSION_MISSING_FACILITY_STATUSES)
4381 {
4382 uint32_t cFacilityStatuses;
4383 rc = pHlp->pfnSSMGetU32(pSSM, &cFacilityStatuses);
4384 AssertRCReturn(rc, rc);
4385
4386 for (uint32_t i = 0; i < cFacilityStatuses; i++)
4387 {
4388 uint32_t uFacility, fFlags;
4389 uint16_t uStatus;
4390 int64_t iTimeStampNano;
4391
4392 pHlp->pfnSSMGetU32(pSSM, &uFacility);
4393 pHlp->pfnSSMGetU32(pSSM, &fFlags);
4394 pHlp->pfnSSMGetU16(pSSM, &uStatus);
4395 rc = pHlp->pfnSSMGetS64(pSSM, &iTimeStampNano);
4396 AssertRCReturn(rc, rc);
4397
4398 PVMMDEVFACILITYSTATUSENTRY pEntry = vmmdevGetFacilityStatusEntry(pThis, (VBoxGuestFacilityType)uFacility);
4399 AssertLogRelMsgReturn(pEntry,
4400 ("VMMDev: Ran out of entries restoring the guest facility statuses. Saved state has %u.\n", cFacilityStatuses),
4401 VERR_OUT_OF_RESOURCES);
4402 pEntry->enmStatus = (VBoxGuestFacilityStatus)uStatus;
4403 pEntry->fFlags = fFlags;
4404 RTTimeSpecSetNano(&pEntry->TimeSpecTS, iTimeStampNano);
4405 }
4406 }
4407
4408 /*
4409 * Heartbeat.
4410 */
4411 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_HEARTBEAT)
4412 {
4413 pHlp->pfnSSMGetBoolV(pSSM, &pThis->fHeartbeatActive);
4414 pHlp->pfnSSMGetBoolV(pSSM, &pThis->fFlatlined);
4415 pHlp->pfnSSMGetU64V(pSSM, &pThis->nsLastHeartbeatTS);
4416 rc = PDMDevHlpTimerLoad(pDevIns, pThis->hFlatlinedTimer, pSSM);
4417 AssertRCReturn(rc, rc);
4418 if (pThis->fFlatlined)
4419 LogRel(("vmmdevLoadState: Guest has flatlined. Last heartbeat %'RU64 ns before state was saved.\n",
4420 PDMDevHlpTimerGetNano(pDevIns, pThis->hFlatlinedTimer) - pThis->nsLastHeartbeatTS));
4421 }
4422
4423 if (uVersion >= VMMDEV_SAVED_STATE_VERSION_DISPLAY_CHANGE_DATA)
4424 {
4425 pHlp->pfnSSMGetStructEx(pSSM, &pThis->displayChangeData, sizeof(pThis->displayChangeData), 0,
4426 g_aSSMDISPLAYCHANGEDATAStateFields, NULL);
4427 }
4428
4429 /*
4430 * On a resume, we send the capabilities changed message so
4431 * that listeners can sync their state again
4432 */
4433 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pThis->fMouseCapabilities));
4434 if (pThisCC->pDrv)
4435 {
4436 pThisCC->pDrv->pfnUpdateMouseCapabilities(pThisCC->pDrv, pThis->fMouseCapabilities);
4437 if (uVersion >= 10)
4438 pThisCC->pDrv->pfnUpdatePointerShape(pThisCC->pDrv,
4439 /*fVisible=*/!!pThis->fHostCursorRequested,
4440 /*fAlpha=*/false,
4441 /*xHot=*/0, /*yHot=*/0,
4442 /*cx=*/0, /*cy=*/0,
4443 /*pvShape=*/NULL);
4444 }
4445
4446 if (pThis->fu32AdditionsOk)
4447 {
4448 vmmdevLogGuestOsInfo(&pThis->guestInfo);
4449 if (pThisCC->pDrv)
4450 {
4451 if (pThis->guestInfo2.uFullVersion && pThisCC->pDrv->pfnUpdateGuestInfo2)
4452 pThisCC->pDrv->pfnUpdateGuestInfo2(pThisCC->pDrv, pThis->guestInfo2.uFullVersion, pThis->guestInfo2.szName,
4453 pThis->guestInfo2.uRevision, pThis->guestInfo2.fFeatures);
4454 if (pThisCC->pDrv->pfnUpdateGuestInfo)
4455 pThisCC->pDrv->pfnUpdateGuestInfo(pThisCC->pDrv, &pThis->guestInfo);
4456
4457 if (pThisCC->pDrv->pfnUpdateGuestStatus)
4458 {
4459 for (uint32_t i = 0; i < pThis->cFacilityStatuses; i++) /* ascending order! */
4460 if ( pThis->aFacilityStatuses[i].enmStatus != VBoxGuestFacilityStatus_Inactive
4461 || !pThis->aFacilityStatuses[i].fFixed)
4462 pThisCC->pDrv->pfnUpdateGuestStatus(pThisCC->pDrv,
4463 pThis->aFacilityStatuses[i].enmFacility,
4464 (uint16_t)pThis->aFacilityStatuses[i].enmStatus,
4465 pThis->aFacilityStatuses[i].fFlags,
4466 &pThis->aFacilityStatuses[i].TimeSpecTS);
4467 }
4468 }
4469 }
4470 if (pThisCC->pDrv && pThisCC->pDrv->pfnUpdateGuestCapabilities)
4471 pThisCC->pDrv->pfnUpdateGuestCapabilities(pThisCC->pDrv, pThis->fGuestCaps);
4472
4473 return VINF_SUCCESS;
4474}
4475
4476/**
4477 * Load state done callback. Notify guest of restore event.
4478 *
4479 * @returns VBox status code.
4480 * @param pDevIns The device instance.
4481 * @param pSSM The handle to the saved state.
4482 */
4483static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4484{
4485 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4486 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4487 RT_NOREF(pSSM);
4488
4489#ifdef VBOX_WITH_HGCM
4490 int rc = vmmdevR3HgcmLoadStateDone(pDevIns, pThis, pThisCC);
4491 AssertLogRelRCReturn(rc, rc);
4492#endif /* VBOX_WITH_HGCM */
4493
4494 /* Reestablish the acceleration status. */
4495 if ( pThis->u32VideoAccelEnabled
4496 && pThisCC->pDrv)
4497 pThisCC->pDrv->pfnVideoAccelEnable(pThisCC->pDrv, !!pThis->u32VideoAccelEnabled, &pThisCC->pVMMDevRAMR3->vbvaMemory);
4498
4499 VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_RESTORED);
4500
4501 return VINF_SUCCESS;
4502}
4503
4504
4505/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
4506
4507/**
4508 * (Re-)initializes the MMIO2 data.
4509 *
4510 * @param pThisCC The VMMDev ring-3 instance data.
4511 */
4512static void vmmdevInitRam(PVMMDEVCC pThisCC)
4513{
4514 memset(pThisCC->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
4515 pThisCC->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
4516 pThisCC->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
4517}
4518
4519
4520/**
4521 * @interface_method_impl{PDMDEVREG,pfnReset}
4522 */
4523static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
4524{
4525 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4526 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4527 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
4528 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
4529
4530 /*
4531 * Reset the mouse integration feature bits
4532 */
4533 if (pThis->fMouseCapabilities & VMMDEV_MOUSE_GUEST_MASK)
4534 {
4535 pThis->fMouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
4536 /* notify the connector */
4537 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pThis->fMouseCapabilities));
4538 pThisCC->pDrv->pfnUpdateMouseCapabilities(pThisCC->pDrv, pThis->fMouseCapabilities);
4539 }
4540 pThis->fHostCursorRequested = false;
4541
4542 /* re-initialize the VMMDev memory */
4543 if (pThisCC->pVMMDevRAMR3)
4544 vmmdevInitRam(pThisCC);
4545
4546 /* credentials have to go away (by default) */
4547 VMMDEVCREDS *pCredentials = pThisCC->pCredentials;
4548 if (pCredentials)
4549 {
4550 if (!pThis->fKeepCredentials)
4551 {
4552 RT_ZERO(pCredentials->Logon.szUserName);
4553 RT_ZERO(pCredentials->Logon.szPassword);
4554 RT_ZERO(pCredentials->Logon.szDomain);
4555 }
4556 RT_ZERO(pCredentials->Judge.szUserName);
4557 RT_ZERO(pCredentials->Judge.szPassword);
4558 RT_ZERO(pCredentials->Judge.szDomain);
4559 }
4560
4561 /* Reset means that additions will report again. */
4562 const bool fVersionChanged = pThis->fu32AdditionsOk
4563 || pThis->guestInfo.interfaceVersion
4564 || pThis->guestInfo.osType != VBOXOSTYPE_Unknown;
4565 if (fVersionChanged)
4566 Log(("vmmdevReset: fu32AdditionsOk=%d additionsVersion=%x osType=%#x\n",
4567 pThis->fu32AdditionsOk, pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
4568 pThis->fu32AdditionsOk = false;
4569 memset (&pThis->guestInfo, 0, sizeof (pThis->guestInfo));
4570 RT_ZERO(pThis->guestInfo2);
4571 const bool fCapsChanged = pThis->fGuestCaps != 0; /* Report transition to 0. */
4572 pThis->fGuestCaps = 0;
4573
4574 /* Clear facilities. No need to tell Main as it will get a
4575 pfnUpdateGuestInfo callback. */
4576 RTTIMESPEC TimeStampNow;
4577 RTTimeNow(&TimeStampNow);
4578 uint32_t iFacility = pThis->cFacilityStatuses;
4579 while (iFacility-- > 0)
4580 {
4581 pThis->aFacilityStatuses[iFacility].enmStatus = VBoxGuestFacilityStatus_Inactive;
4582 pThis->aFacilityStatuses[iFacility].TimeSpecTS = TimeStampNow;
4583 }
4584
4585 /* clear pending display change request. */
4586 for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
4587 {
4588 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
4589 memset(&pRequest->lastReadDisplayChangeRequest, 0, sizeof(pRequest->lastReadDisplayChangeRequest));
4590 pRequest->lastReadDisplayChangeRequest.fDisplayFlags = VMMDEV_DISPLAY_DISABLED;
4591 pRequest->lastReadDisplayChangeRequest.idDisplay = i;
4592 }
4593 pThis->displayChangeData.iCurrentMonitor = 0;
4594 pThis->displayChangeData.fGuestSentChangeEventAck = false;
4595
4596 /* disable seamless mode */
4597 pThis->fLastSeamlessEnabled = false;
4598
4599 /* disabled memory ballooning */
4600 pThis->cMbMemoryBalloonLast = 0;
4601
4602 /* disabled statistics updating */
4603 pThis->cSecsLastStatInterval = 0;
4604
4605#ifdef VBOX_WITH_HGCM
4606 /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled. */
4607 pThisCC->u32HGCMEnabled = 0;
4608#endif
4609
4610 /*
4611 * Deactive heartbeat.
4612 */
4613 if (pThis->fHeartbeatActive)
4614 {
4615 PDMDevHlpTimerStop(pDevIns, pThis->hFlatlinedTimer);
4616 pThis->fFlatlined = false;
4617 pThis->fHeartbeatActive = true;
4618 }
4619
4620 /*
4621 * Clear the event variables.
4622 *
4623 * XXX By design we should NOT clear pThis->fHostEventFlags because it is designed
4624 * that way so host events do not depend on guest resets. However, the pending
4625 * event flags actually _were_ cleared since ages so we mask out events from
4626 * clearing which we really need to survive the reset. See xtracker 5767.
4627 */
4628 pThis->fHostEventFlags &= VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
4629 pThis->fGuestFilterMask = 0;
4630 pThis->fNewGuestFilterMask = 0;
4631 pThis->fNewGuestFilterMaskValid = 0;
4632
4633 /*
4634 * Call the update functions as required.
4635 */
4636 if (fVersionChanged && pThisCC->pDrv && pThisCC->pDrv->pfnUpdateGuestInfo)
4637 pThisCC->pDrv->pfnUpdateGuestInfo(pThisCC->pDrv, &pThis->guestInfo);
4638 if (fCapsChanged && pThisCC->pDrv && pThisCC->pDrv->pfnUpdateGuestCapabilities)
4639 pThisCC->pDrv->pfnUpdateGuestCapabilities(pThisCC->pDrv, pThis->fGuestCaps);
4640
4641 /*
4642 * Generate a unique session id for this VM; it will be changed for each start, reset or restore.
4643 * This can be used for restore detection inside the guest.
4644 */
4645 pThis->idSession = ASMReadTSC();
4646
4647 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4648}
4649
4650
4651#ifdef VBOX_WITH_RAW_MODE_KEEP
4652/**
4653 * @interface_method_impl{PDMDEVREG,pfnRelocate}
4654 */
4655static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
4656{
4657 if (offDelta)
4658 {
4659 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4660 LogFlow(("vmmdevRelocate: offDelta=%RGv\n", offDelta));
4661
4662 if (pThis->pVMMDevRAMRC)
4663 pThis->pVMMDevRAMRC += offDelta;
4664 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
4665 }
4666}
4667#endif
4668
4669
4670/**
4671 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4672 */
4673static DECLCALLBACK(int) vmmdevDestruct(PPDMDEVINS pDevIns)
4674{
4675 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4676 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4677
4678 /*
4679 * Wipe and free the credentials.
4680 */
4681 VMMDEVCREDS *pCredentials = pThisCC->pCredentials;
4682 pThisCC->pCredentials = NULL;
4683 if (pCredentials)
4684 {
4685 if (pThisCC->fSaferCredentials)
4686 RTMemSaferFree(pCredentials, sizeof(*pCredentials));
4687 else
4688 {
4689 RTMemWipeThoroughly(pCredentials, sizeof(*pCredentials), 10);
4690 RTMemFree(pCredentials);
4691 }
4692 }
4693
4694#ifdef VBOX_WITH_HGCM
4695 /*
4696 * Everything HGCM.
4697 */
4698 vmmdevR3HgcmDestroy(pDevIns, PDMDEVINS_2_DATA(pDevIns, PVMMDEV), pThisCC);
4699#endif
4700
4701 /*
4702 * Free the request buffers.
4703 */
4704 for (uint32_t iCpu = 0; iCpu < RT_ELEMENTS(pThisCC->apReqBufs); iCpu++)
4705 {
4706 RTMemPageFree(pThisCC->apReqBufs[iCpu], _4K);
4707 pThisCC->apReqBufs[iCpu] = NULL;
4708 }
4709
4710#ifndef VBOX_WITHOUT_TESTING_FEATURES
4711 /*
4712 * Clean up the testing device.
4713 */
4714 vmmdevR3TestingTerminate(pDevIns);
4715#endif
4716
4717 return VINF_SUCCESS;
4718}
4719
4720
4721/**
4722 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4723 */
4724static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4725{
4726 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4727 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
4728 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
4729 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4730 int rc;
4731
4732 Assert(iInstance == 0);
4733 RT_NOREF(iInstance);
4734
4735 /*
4736 * Initialize data (most of it anyway).
4737 */
4738 pThisCC->pDevIns = pDevIns;
4739
4740 pThis->hFlatlinedTimer = NIL_TMTIMERHANDLE;
4741 pThis->hIoPortBackdoorLog = NIL_IOMIOPORTHANDLE;
4742 pThis->hIoPortAltTimesync = NIL_IOMIOPORTHANDLE;
4743 pThis->hIoPortReq = NIL_IOMIOPORTHANDLE;
4744 pThis->hIoPortFast = NIL_IOMIOPORTHANDLE;
4745 pThis->hMmio2VMMDevRAM = NIL_PGMMMIO2HANDLE;
4746 pThis->hMmio2Heap = NIL_PGMMMIO2HANDLE;
4747#ifndef VBOX_WITHOUT_TESTING_FEATURES
4748 pThis->hIoPortTesting = NIL_IOMIOPORTHANDLE;
4749 pThis->hMmioTesting = NIL_IOMMMIOHANDLE;
4750 pThis->hTestingLockEvt = NIL_SUPSEMEVENT;
4751#endif
4752
4753 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4754 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
4755
4756 /* PCI vendor, just a free bogus value */
4757 PDMPciDevSetVendorId(pPciDev, 0x80ee);
4758 /* device ID */
4759 PDMPciDevSetDeviceId(pPciDev, 0xcafe);
4760 /* class sub code (other type of system peripheral) */
4761 PDMPciDevSetClassSub(pPciDev, 0x80);
4762 /* class base code (base system peripheral) */
4763 PDMPciDevSetClassBase(pPciDev, 0x08);
4764 /* header type */
4765 PDMPciDevSetHeaderType(pPciDev, 0x00);
4766 /* interrupt on pin 0 */
4767 PDMPciDevSetInterruptPin(pPciDev, 0x01);
4768
4769 RTTIMESPEC TimeStampNow;
4770 RTTimeNow(&TimeStampNow);
4771 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxGuestDriver, true /*fFixed*/, &TimeStampNow);
4772 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxService, true /*fFixed*/, &TimeStampNow);
4773 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_VBoxTrayClient, true /*fFixed*/, &TimeStampNow);
4774 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Seamless, true /*fFixed*/, &TimeStampNow);
4775 vmmdevAllocFacilityStatusEntry(pThis, VBoxGuestFacilityType_Graphics, true /*fFixed*/, &TimeStampNow);
4776 Assert(pThis->cFacilityStatuses == 5);
4777
4778 /* disable all screens (no better hints known yet). */
4779 /** @todo r=klaus need a way to represent "no hint known" */
4780 for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
4781 {
4782 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
4783 pRequest->displayChangeRequest.fDisplayFlags = VMMDEV_DISPLAY_DISABLED;
4784 pRequest->displayChangeRequest.idDisplay = i;
4785 pRequest->lastReadDisplayChangeRequest.fDisplayFlags = VMMDEV_DISPLAY_DISABLED;
4786 pRequest->lastReadDisplayChangeRequest.idDisplay = i;
4787 }
4788
4789 /*
4790 * Interfaces
4791 */
4792 /* IBase */
4793 pThisCC->IBase.pfnQueryInterface = vmmdevPortQueryInterface;
4794
4795 /* VMMDev port */
4796 pThisCC->IPort.pfnQueryAbsoluteMouse = vmmdevIPort_QueryAbsoluteMouse;
4797 pThisCC->IPort.pfnSetAbsoluteMouse = vmmdevIPort_SetAbsoluteMouse ;
4798 pThisCC->IPort.pfnQueryMouseCapabilities = vmmdevIPort_QueryMouseCapabilities;
4799 pThisCC->IPort.pfnUpdateMouseCapabilities = vmmdevIPort_UpdateMouseCapabilities;
4800 pThisCC->IPort.pfnRequestDisplayChange = vmmdevIPort_RequestDisplayChange;
4801 pThisCC->IPort.pfnSetCredentials = vmmdevIPort_SetCredentials;
4802 pThisCC->IPort.pfnVBVAChange = vmmdevIPort_VBVAChange;
4803 pThisCC->IPort.pfnRequestSeamlessChange = vmmdevIPort_RequestSeamlessChange;
4804 pThisCC->IPort.pfnSetMemoryBalloon = vmmdevIPort_SetMemoryBalloon;
4805 pThisCC->IPort.pfnSetStatisticsInterval = vmmdevIPort_SetStatisticsInterval;
4806 pThisCC->IPort.pfnVRDPChange = vmmdevIPort_VRDPChange;
4807 pThisCC->IPort.pfnCpuHotUnplug = vmmdevIPort_CpuHotUnplug;
4808 pThisCC->IPort.pfnCpuHotPlug = vmmdevIPort_CpuHotPlug;
4809
4810 /* Shared folder LED */
4811 pThisCC->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
4812 pThisCC->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
4813
4814#ifdef VBOX_WITH_HGCM
4815 /* HGCM port */
4816 pThisCC->IHGCMPort.pfnCompleted = hgcmR3Completed;
4817 pThisCC->IHGCMPort.pfnIsCmdRestored = hgcmR3IsCmdRestored;
4818 pThisCC->IHGCMPort.pfnIsCmdCancelled = hgcmR3IsCmdCancelled;
4819 pThisCC->IHGCMPort.pfnGetRequestor = hgcmR3GetRequestor;
4820 pThisCC->IHGCMPort.pfnGetVMMDevSessionId = hgcmR3GetVMMDevSessionId;
4821#endif
4822
4823 pThisCC->pCredentials = (VMMDEVCREDS *)RTMemSaferAllocZ(sizeof(*pThisCC->pCredentials));
4824 if (pThisCC->pCredentials)
4825 pThisCC->fSaferCredentials = true;
4826 else
4827 {
4828 pThisCC->pCredentials = (VMMDEVCREDS *)RTMemAllocZ(sizeof(*pThisCC->pCredentials));
4829 AssertReturn(pThisCC->pCredentials, VERR_NO_MEMORY);
4830 }
4831
4832
4833 /*
4834 * Validate and read the configuration.
4835 */
4836 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
4837 "AllowGuestToSaveState|"
4838 "GetHostTimeDisabled|"
4839 "BackdoorLogDisabled|"
4840 "KeepCredentials|"
4841 "HeapEnabled|"
4842 "GuestCoreDumpEnabled|"
4843 "GuestCoreDumpDir|"
4844 "GuestCoreDumpCount|"
4845 "HeartbeatInterval|"
4846 "HeartbeatTimeout|"
4847 "MmioReq|"
4848 "TestingEnabled|"
4849 "TestingMMIO|"
4850 "TestingXmlOutputFile|"
4851 "TestingCfgDword0|"
4852 "TestingCfgDword1|"
4853 "TestingCfgDword2|"
4854 "TestingCfgDword3|"
4855 "TestingCfgDword4|"
4856 "TestingCfgDword5|"
4857 "TestingCfgDword6|"
4858 "TestingCfgDword7|"
4859 "TestingCfgDword8|"
4860 "TestingCfgDword9|"
4861 "HGCMHeapBudgetDefault|"
4862 "HGCMHeapBudgetLegacy|"
4863 "HGCMHeapBudgetVBoxGuest|"
4864 "HGCMHeapBudgetOtherDrv|"
4865 "HGCMHeapBudgetRoot|"
4866 "HGCMHeapBudgetSystem|"
4867 "HGCMHeapBudgetReserved1|"
4868 "HGCMHeapBudgetUser|"
4869 "HGCMHeapBudgetGuest"
4870 ,
4871 "");
4872
4873 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "AllowGuestToSaveState", &pThis->fAllowGuestToSaveState, true);
4874 if (RT_FAILURE(rc))
4875 return PDMDEV_SET_ERROR(pDevIns, rc,
4876 N_("Configuration error: Failed querying \"AllowGuestToSaveState\" as a boolean"));
4877
4878 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
4879 if (RT_FAILURE(rc))
4880 return PDMDEV_SET_ERROR(pDevIns, rc,
4881 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
4882
4883 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "BackdoorLogDisabled", &pThis->fBackdoorLogDisabled, false);
4884 if (RT_FAILURE(rc))
4885 return PDMDEV_SET_ERROR(pDevIns, rc,
4886 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
4887
4888 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "KeepCredentials", &pThis->fKeepCredentials, false);
4889 if (RT_FAILURE(rc))
4890 return PDMDEV_SET_ERROR(pDevIns, rc,
4891 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
4892
4893 /* The heap is of no use on non x86 guest architectures. */
4894 static const bool fHeapEnabledDef = PDMDevHlpCpuIsGuestArchX86(pDevIns);
4895 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "HeapEnabled", &pThis->fHeapEnabled, fHeapEnabledDef);
4896 if (RT_FAILURE(rc))
4897 return PDMDEV_SET_ERROR(pDevIns, rc,
4898 N_("Configuration error: Failed querying \"HeapEnabled\" as a boolean"));
4899
4900 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "GuestCoreDumpEnabled", &pThis->fGuestCoreDumpEnabled, false);
4901 if (RT_FAILURE(rc))
4902 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"GuestCoreDumpEnabled\" as a boolean"));
4903
4904 char *pszGuestCoreDumpDir = NULL;
4905 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "GuestCoreDumpDir", &pszGuestCoreDumpDir, "");
4906 if (RT_FAILURE(rc))
4907 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"GuestCoreDumpDir\" as a string"));
4908
4909 RTStrCopy(pThis->szGuestCoreDumpDir, sizeof(pThis->szGuestCoreDumpDir), pszGuestCoreDumpDir);
4910 PDMDevHlpMMHeapFree(pDevIns, pszGuestCoreDumpDir);
4911
4912 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GuestCoreDumpCount", &pThis->cGuestCoreDumps, 3);
4913 if (RT_FAILURE(rc))
4914 return PDMDEV_SET_ERROR(pDevIns, rc,
4915 N_("Configuration error: Failed querying \"GuestCoreDumpCount\" as a 32-bit unsigned integer"));
4916
4917 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "HeartbeatInterval", &pThis->cNsHeartbeatInterval, VMMDEV_HEARTBEAT_DEFAULT_INTERVAL);
4918 if (RT_FAILURE(rc))
4919 return PDMDEV_SET_ERROR(pDevIns, rc,
4920 N_("Configuration error: Failed querying \"HeartbeatInterval\" as a 64-bit unsigned integer"));
4921 if (pThis->cNsHeartbeatInterval < RT_NS_100MS / 2)
4922 return PDMDEV_SET_ERROR(pDevIns, rc,
4923 N_("Configuration error: Heartbeat interval \"HeartbeatInterval\" too small"));
4924
4925 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "HeartbeatTimeout", &pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval * 2);
4926 if (RT_FAILURE(rc))
4927 return PDMDEV_SET_ERROR(pDevIns, rc,
4928 N_("Configuration error: Failed querying \"HeartbeatTimeout\" as a 64-bit unsigned integer"));
4929 if (pThis->cNsHeartbeatTimeout < RT_NS_100MS)
4930 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" too small"));
4931 if (pThis->cNsHeartbeatTimeout <= pThis->cNsHeartbeatInterval + RT_NS_10MS)
4932 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4933 N_("Configuration error: Heartbeat timeout \"HeartbeatTimeout\" value (%'ull ns) is too close to the interval (%'ull ns)"),
4934 pThis->cNsHeartbeatTimeout, pThis->cNsHeartbeatInterval);
4935
4936 /* 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. */
4937 static const bool fMmioReqEnabledDef = !PDMDevHlpCpuIsGuestArchX86(pDevIns);
4938 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "MmioReq", &pThis->fMmioReq, fMmioReqEnabledDef);
4939 if (RT_FAILURE(rc))
4940 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"MmioReq\" as a boolean"));
4941
4942#ifndef VBOX_WITHOUT_TESTING_FEATURES
4943 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TestingEnabled", &pThis->fTestingEnabled, false);
4944 if (RT_FAILURE(rc))
4945 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestingEnabled\" as a boolean"));
4946 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TestingMMIO", &pThis->fTestingMMIO, false);
4947 if (RT_FAILURE(rc))
4948 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestingMMIO\" as a boolean"));
4949 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "TestingXmlOutputFile", &pThisCC->pszTestingXmlOutput, NULL);
4950 if (RT_FAILURE(rc))
4951 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"TestingXmlOutputFile\" as a string"));
4952
4953 for (unsigned i = 0; i < RT_ELEMENTS(pThis->au32TestingCfgDwords); i++)
4954 {
4955 char szName[32];
4956 RTStrPrintf(szName, sizeof(szName), "TestingCfgDword%u", i);
4957 rc = pHlp->pfnCFGMQueryU32Def(pCfg, szName, &pThis->au32TestingCfgDwords[i], 0);
4958 if (RT_FAILURE(rc))
4959 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4960 N_("Configuration error: Failed querying \"%s\" as a string"), szName);
4961 }
4962
4963
4964 /** @todo image-to-load-filename? */
4965#endif
4966
4967#ifdef VBOX_WITH_HGCM
4968 /*
4969 * Heap budgets for HGCM requestor categories. Take the available host
4970 * memory as a rough hint of how much we can handle.
4971 */
4972 uint64_t cbDefaultBudget = 0;
4973 if (RT_FAILURE(RTSystemQueryTotalRam(&cbDefaultBudget)))
4974 cbDefaultBudget = 8 * _1G64;
4975 LogFunc(("RTSystemQueryTotalRam -> %'RU64 (%RX64)\n", cbDefaultBudget, cbDefaultBudget));
4976# if ARCH_BITS == 32
4977 cbDefaultBudget = RT_MIN(cbDefaultBudget, _512M);
4978# endif
4979 cbDefaultBudget /= 8; /* One eighth of physical memory ... */
4980 cbDefaultBudget /= RT_ELEMENTS(pThisCC->aHgcmAcc); /* over 3 accounting categories. (8GiB -> 341MiB) */
4981 cbDefaultBudget = RT_MIN(cbDefaultBudget, _1G); /* max 1024MiB */
4982 cbDefaultBudget = RT_MAX(cbDefaultBudget, _32M); /* min 32MiB */
4983 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "HGCMHeapBudgetDefault", &cbDefaultBudget, cbDefaultBudget);
4984 if (RT_FAILURE(rc))
4985 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed querying \"HGCMHeapBudgetDefault\" as a 64-bit unsigned integer"));
4986
4987 LogRel(("VMMDev: cbDefaultBudget: %'RU64 (%RX64)\n", cbDefaultBudget, cbDefaultBudget));
4988 static const struct { const char *pszName; unsigned idx; } s_aCfgHeapBudget[] =
4989 {
4990 { "HGCMHeapBudgetKernel", VMMDEV_HGCM_CATEGORY_KERNEL },
4991 { "HGCMHeapBudgetRoot", VMMDEV_HGCM_CATEGORY_ROOT },
4992 { "HGCMHeapBudgetUser", VMMDEV_HGCM_CATEGORY_USER },
4993 };
4994 AssertCompile(RT_ELEMENTS(s_aCfgHeapBudget) == RT_ELEMENTS(pThisCC->aHgcmAcc));
4995 for (uintptr_t i = 0; i < RT_ELEMENTS(s_aCfgHeapBudget); i++)
4996 {
4997 uintptr_t const idx = s_aCfgHeapBudget[i].idx;
4998 rc = pHlp->pfnCFGMQueryU64Def(pCfg, s_aCfgHeapBudget[i].pszName,
4999 &pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig, cbDefaultBudget);
5000 if (RT_FAILURE(rc))
5001 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5002 N_("Configuration error: Failed querying \"%s\" as a 64-bit unsigned integer"),
5003 s_aCfgHeapBudget[i].pszName);
5004 pThisCC->aHgcmAcc[idx].cbHeapBudget = pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig;
5005 if (pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig != cbDefaultBudget)
5006 LogRel(("VMMDev: %s: %'RU64 (%#RX64)\n", s_aCfgHeapBudget[i].pszName,
5007 pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig, pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig));
5008
5009 const char * const pszCatName = &s_aCfgHeapBudget[i].pszName[sizeof("HGCMHeapBudget") - 1];
5010 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].cbHeapBudget, STAMTYPE_U64, STAMVISIBILITY_ALWAYS,
5011 STAMUNIT_BYTES, "Currently available budget", "HGCM-%s/BudgetAvailable", pszCatName);
5012 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].cbHeapBudgetConfig, STAMTYPE_U64, STAMVISIBILITY_ALWAYS,
5013 STAMUNIT_BYTES, "Configured budget", "HGCM-%s/BudgetConfig", pszCatName);
5014 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].StateMsgHeapUsage, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
5015 STAMUNIT_BYTES_PER_CALL, "Message heap usage", "HGCM-%s/MessageHeapUsage", pszCatName);
5016 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aHgcmAcc[idx].StatBudgetOverruns, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
5017 STAMUNIT_BYTES, "Budget overruns and allocation errors", "HGCM-%s/BudgetOverruns", pszCatName);
5018 }
5019#endif
5020
5021 /*
5022 * <missing comment>
5023 */
5024 pThis->cbGuestRAM = PDMDevHlpMMPhysGetRamSize(pDevIns);
5025
5026 /*
5027 * We do our own locking entirely. So, install NOP critsect for the device
5028 * and create our own critsect for use where it really matters (++).
5029 */
5030 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5031 AssertRCReturn(rc, rc);
5032 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev#%u", iInstance);
5033 AssertRCReturn(rc, rc);
5034
5035 /*
5036 * Register the backdoor logging port
5037 */
5038 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, RTLOG_DEBUG_PORT, 1, vmmdevBackdoorLog, NULL /*pfnIn*/,
5039 "VMMDev backdoor logging", NULL, &pThis->hIoPortBackdoorLog);
5040 AssertRCReturn(rc, rc);
5041
5042#ifdef VMMDEV_WITH_ALT_TIMESYNC
5043 /*
5044 * Alternative timesync source.
5045 *
5046 * This was orignally added for creating a simple time sync service in an
5047 * OpenBSD guest without requiring VBoxGuest and VBoxService to be ported
5048 * first. We keep it in case it comes in handy.
5049 */
5050 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x505, 1, vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead,
5051 "VMMDev timesync backdoor", NULL /*paExtDescs*/, &pThis->hIoPortAltTimesync);
5052 AssertRCReturn(rc, rc);
5053#endif
5054
5055 /*
5056 * Register the PCI device.
5057 */
5058 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
5059 if (RT_FAILURE(rc))
5060 return rc;
5061 if (pPciDev->uDevFn != 32 || iInstance != 0)
5062 Log(("!!WARNING!!: pThis->PciDev.uDevFn=%d (ignore if testcase or no started by Main)\n", pPciDev->uDevFn));
5063
5064 /*
5065 * The I/O ports, PCI region #0. This has two separate I/O port mappings in it,
5066 * so we have to do it via the mapper callback.
5067 */
5068 rc = PDMDevHlpIoPortCreate(pDevIns, 1 /*cPorts*/, pPciDev, RT_MAKE_U32(0, 0), vmmdevPioRequestHandler, NULL /*pfnIn*/,
5069 NULL /*pvUser*/, "VMMDev Request Handler", NULL, &pThis->hIoPortReq);
5070 AssertRCReturn(rc, rc);
5071
5072 rc = PDMDevHlpIoPortCreate(pDevIns, 1 /*cPorts*/, pPciDev, RT_MAKE_U32(1, 0), vmmdevPioFastRequestHandler,
5073 vmmdevPioFastRequestIrqAck, NULL, "VMMDev Fast R0/RC Requests", NULL /*pvUser*/, &pThis->hIoPortFast);
5074 AssertRCReturn(rc, rc);
5075
5076 rc = PDMDevHlpPCIIORegionRegisterIoCustom(pDevIns, 0, 0x20, vmmdevIOPortRegionMap);
5077 AssertRCReturn(rc, rc);
5078
5079 /*
5080 * Allocate and initialize the MMIO2 memory, PCI region #1.
5081 */
5082 rc = PDMDevHlpPCIIORegionCreateMmio2(pDevIns, 1 /*iPciRegion*/, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, "VMMDev",
5083 (void **)&pThisCC->pVMMDevRAMR3, &pThis->hMmio2VMMDevRAM);
5084 if (RT_FAILURE(rc))
5085 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5086 N_("Failed to create the %u (%#x) byte MMIO2 region for the VMM device"),
5087 VMMDEV_RAM_SIZE, VMMDEV_RAM_SIZE);
5088 vmmdevInitRam(pThisCC);
5089
5090 /*
5091 * The MMIO2 heap (used for real-mode VT-x trickery), PCI region #2.
5092 */
5093 if (pThis->fHeapEnabled)
5094 {
5095 rc = PDMDevHlpPCIIORegionCreateMmio2Ex(pDevIns, 2 /*iPciRegion*/, VMMDEV_HEAP_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH,
5096 0 /*fFlags*/, vmmdevMmio2HeapRegionMap, "VMMDev Heap",
5097 (void **)&pThisCC->pVMMDevHeapR3, &pThis->hMmio2Heap);
5098 if (RT_FAILURE(rc))
5099 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5100 N_("Failed to create the %u (%#x) bytes MMIO2 heap region for the VMM device"),
5101 VMMDEV_HEAP_SIZE, VMMDEV_HEAP_SIZE);
5102
5103 /* Register the memory area with PDM so HM can access it before it's mapped. */
5104 rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThisCC->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
5105 AssertLogRelRCReturn(rc, rc);
5106 }
5107
5108 if (pThis->fMmioReq)
5109 {
5110 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 3 /*iPciRegion*/, VMMDEV_MMIO_SIZE, PCI_ADDRESS_SPACE_MEM,
5111 vmmdevMmioWrite, vmmdevMmioRead, NULL,
5112 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
5113 "VMMDev MMIO Request Handler", &pThis->hMmioReq);
5114 AssertRCReturn(rc, rc);
5115 }
5116
5117#ifndef VBOX_WITHOUT_TESTING_FEATURES
5118 /*
5119 * Initialize testing.
5120 */
5121 rc = vmmdevR3TestingInitialize(pDevIns);
5122 if (RT_FAILURE(rc))
5123 return rc;
5124#endif
5125
5126 /*
5127 * Get the corresponding connector interface
5128 */
5129 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "VMM Driver Port");
5130 if (RT_SUCCESS(rc))
5131 {
5132 pThisCC->pDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIVMMDEVCONNECTOR);
5133 AssertMsgReturn(pThisCC->pDrv, ("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
5134#ifdef VBOX_WITH_HGCM
5135 pThisCC->pHGCMDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIHGCMCONNECTOR);
5136 if (!pThisCC->pHGCMDrv)
5137 {
5138 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Rrc\n", rc));
5139 /* this is not actually an error, just means that there is no support for HGCM */
5140 }
5141#endif
5142 /* Query the initial balloon size. */
5143 AssertPtr(pThisCC->pDrv->pfnQueryBalloonSize);
5144 rc = pThisCC->pDrv->pfnQueryBalloonSize(pThisCC->pDrv, &pThis->cMbMemoryBalloon);
5145 AssertRC(rc);
5146
5147 Log(("Initial balloon size %x\n", pThis->cMbMemoryBalloon));
5148 }
5149 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5150 {
5151 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
5152 rc = VINF_SUCCESS;
5153 }
5154 else
5155 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Rrc\n", rc), rc);
5156
5157 /*
5158 * Attach status driver for shared folders (optional).
5159 */
5160 PPDMIBASE pBase;
5161 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThisCC->IBase, &pBase, "Status Port");
5162 if (RT_SUCCESS(rc))
5163 pThisCC->SharedFolders.pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5164 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
5165 {
5166 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
5167 return rc;
5168 }
5169
5170 /*
5171 * Register saved state and init the HGCM CmdList critsect.
5172 */
5173 rc = PDMDevHlpSSMRegisterEx(pDevIns, VMMDEV_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
5174 NULL, vmmdevLiveExec, NULL,
5175 NULL, vmmdevSaveExec, NULL,
5176 NULL, vmmdevLoadExec, vmmdevLoadStateDone);
5177 AssertRCReturn(rc, rc);
5178
5179 /*
5180 * Create heartbeat checking timer.
5181 */
5182 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vmmDevHeartbeatFlatlinedTimer, pThis,
5183 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, "Heartbeat flatlined", &pThis->hFlatlinedTimer);
5184 AssertRCReturn(rc, rc);
5185
5186#ifdef VBOX_WITH_HGCM
5187 rc = vmmdevR3HgcmInit(pThisCC);
5188 AssertRCReturn(rc, rc);
5189#endif
5190
5191 /*
5192 * In this version of VirtualBox the GUI checks whether "needs host cursor"
5193 * changes.
5194 */
5195 pThis->fMouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
5196
5197 /*
5198 * In this version of VirtualBox full mouse state can be provided to the guest over DevVMM.
5199 */
5200 pThis->fMouseCapabilities |= VMMDEV_MOUSE_HOST_SUPPORTS_FULL_STATE_PROTOCOL;
5201
5202 /*
5203 * Statistics.
5204 */
5205 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5206 "Memory balloon size", "BalloonChunks");
5207 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatFastIrqAckR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5208 "Fast IRQ acknowledgments handled in ring-3.", "FastIrqAckR3");
5209 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatFastIrqAckRZ, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5210 "Fast IRQ acknowledgments handled in ring-0 or raw-mode.", "FastIrqAckRZ");
5211 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatSlowIrqAck, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5212 "Slow IRQ acknowledgments (old style).", "SlowIrqAck");
5213 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatReqBufAllocs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5214 "Times a larger request buffer was required.", "LargeReqBufAllocs");
5215#ifdef VBOX_WITH_HGCM
5216 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmCmdArrival, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
5217 "Profiling HGCM call arrival processing", "/HGCM/MsgArrival");
5218 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmCmdCompletion, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
5219 "Profiling HGCM call completion processing", "/HGCM/MsgCompletion");
5220 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmCmdTotal, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
5221 "Profiling whole HGCM call.", "/HGCM/MsgTotal");
5222 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmLargeCmdAllocs,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5223 "Times the allocation cache could not be used.", "/HGCM/LargeCmdAllocs");
5224 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->StatHgcmFailedPageListLocking,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
5225 "Times no-bounce page list locking failed.", "/HGCM/FailedPageListLocking");
5226#endif
5227
5228 /*
5229 * Generate a unique session id for this VM; it will be changed for each
5230 * start, reset or restore. This can be used for restore detection inside
5231 * the guest.
5232 */
5233 pThis->idSession = ASMReadTSC();
5234 return rc;
5235}
5236
5237#else /* !IN_RING3 */
5238
5239/**
5240 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5241 */
5242static DECLCALLBACK(int) vmmdevRZConstruct(PPDMDEVINS pDevIns)
5243{
5244 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5245 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
5246 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
5247
5248 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5249 AssertRCReturn(rc, rc);
5250
5251#if 0
5252 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortBackdoorLog, vmmdevBackdoorLog, NULL /*pfnIn*/, NULL /*pvUser*/);
5253 AssertRCReturn(rc, rc);
5254#endif
5255#if 0 && defined(VMMDEV_WITH_ALT_TIMESYNC)
5256 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortAltTimesync, vmmdevAltTimeSyncWrite, vmmdevAltTimeSyncRead, NULL);
5257 AssertRCReturn(rc, rc);
5258#endif
5259
5260 /*
5261 * We map the first page of the VMMDevRAM into raw-mode and kernel contexts so we
5262 * can handle interrupt acknowledge requests more timely (vmmdevPioFastRequestIrqAck).
5263 */
5264 rc = PDMDevHlpMmio2SetUpContext(pDevIns, pThis->hMmio2VMMDevRAM, 0, VMMDEV_PAGE_SIZE, (void **)&pThisCC->CTX_SUFF(pVMMDevRAM));
5265 AssertRCReturn(rc, rc);
5266
5267 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortFast, vmmdevPioFastRequestHandler, vmmdevPioFastRequestIrqAck, NULL);
5268 AssertRCReturn(rc, rc);
5269
5270 if (pThis->fMmioReq)
5271 {
5272 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioReq, vmmdevMmioWrite, vmmdevMmioRead, NULL /*pvUser*/);
5273 AssertRCReturn(rc, rc);
5274 }
5275
5276# ifndef VBOX_WITHOUT_TESTING_FEATURES
5277 /*
5278 * Initialize testing.
5279 */
5280 rc = vmmdevRZTestingInitialize(pDevIns);
5281 AssertRCReturn(rc, rc);
5282# endif
5283
5284 return VINF_SUCCESS;
5285}
5286
5287#endif /* !IN_RING3 */
5288
5289/**
5290 * The device registration structure.
5291 */
5292extern "C" const PDMDEVREG g_DeviceVMMDev =
5293{
5294 /* .u32Version = */ PDM_DEVREG_VERSION,
5295 /* .uReserved0 = */ 0,
5296 /* .szName = */ "VMMDev",
5297 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
5298 /* .fClass = */ PDM_DEVREG_CLASS_VMM_DEV,
5299 /* .cMaxInstances = */ 1,
5300 /* .uSharedVersion = */ 42,
5301 /* .cbInstanceShared = */ sizeof(VMMDEV),
5302 /* .cbInstanceCC = */ sizeof(VMMDEVCC),
5303 /* .cbInstanceRC = */ sizeof(VMMDEVRC),
5304 /* .cMaxPciDevices = */ 1,
5305 /* .cMaxMsixVectors = */ 0,
5306 /* .pszDescription = */ "VirtualBox VMM Device\n",
5307#if defined(IN_RING3)
5308 /* .pszRCMod = */ "VBoxDDRC.rc",
5309 /* .pszR0Mod = */ "VBoxDDR0.r0",
5310 /* .pfnConstruct = */ vmmdevConstruct,
5311 /* .pfnDestruct = */ vmmdevDestruct,
5312# ifdef VBOX_WITH_RAW_MODE_KEEP
5313 /* .pfnRelocate = */ vmmdevRelocate,
5314# else
5315 /* .pfnRelocate = */ NULL,
5316# endif
5317 /* .pfnMemSetup = */ NULL,
5318 /* .pfnPowerOn = */ NULL,
5319 /* .pfnReset = */ vmmdevReset,
5320 /* .pfnSuspend = */ NULL,
5321 /* .pfnResume = */ NULL,
5322 /* .pfnAttach = */ NULL,
5323 /* .pfnDetach = */ NULL,
5324 /* .pfnQueryInterface = */ NULL,
5325 /* .pfnInitComplete = */ NULL,
5326 /* .pfnPowerOff = */ NULL,
5327 /* .pfnSoftReset = */ NULL,
5328 /* .pfnReserved0 = */ NULL,
5329 /* .pfnReserved1 = */ NULL,
5330 /* .pfnReserved2 = */ NULL,
5331 /* .pfnReserved3 = */ NULL,
5332 /* .pfnReserved4 = */ NULL,
5333 /* .pfnReserved5 = */ NULL,
5334 /* .pfnReserved6 = */ NULL,
5335 /* .pfnReserved7 = */ NULL,
5336#elif defined(IN_RING0)
5337 /* .pfnEarlyConstruct = */ NULL,
5338 /* .pfnConstruct = */ vmmdevRZConstruct,
5339 /* .pfnDestruct = */ NULL,
5340 /* .pfnFinalDestruct = */ NULL,
5341 /* .pfnRequest = */ NULL,
5342 /* .pfnReserved0 = */ NULL,
5343 /* .pfnReserved1 = */ NULL,
5344 /* .pfnReserved2 = */ NULL,
5345 /* .pfnReserved3 = */ NULL,
5346 /* .pfnReserved4 = */ NULL,
5347 /* .pfnReserved5 = */ NULL,
5348 /* .pfnReserved6 = */ NULL,
5349 /* .pfnReserved7 = */ NULL,
5350#elif defined(IN_RC)
5351 /* .pfnConstruct = */ vmmdevRZConstruct,
5352 /* .pfnReserved0 = */ NULL,
5353 /* .pfnReserved1 = */ NULL,
5354 /* .pfnReserved2 = */ NULL,
5355 /* .pfnReserved3 = */ NULL,
5356 /* .pfnReserved4 = */ NULL,
5357 /* .pfnReserved5 = */ NULL,
5358 /* .pfnReserved6 = */ NULL,
5359 /* .pfnReserved7 = */ NULL,
5360#else
5361# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5362#endif
5363 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5364};
5365
5366#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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