VirtualBox

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

Last change on this file since 101556 was 100852, checked in by vboxsync, 17 months ago

VMMDev,Main/Appliance: Update the Linux OS subtypes with recent
releases: Oracle Linux 9 and Red Hat 9. bugref:5936

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

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