VirtualBox

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

Last change on this file since 100626 was 100190, 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 [shut up MSC]

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