VirtualBox

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

Last change on this file since 107147 was 107121, checked in by vboxsync, 6 months ago

VBox/ostypes.h+Main/{Global,Appliance}+VMMDev+FE/Qt: Add two new OStypes
for Windows 10 and 11 on ARM. bugref:10732

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

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