VirtualBox

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

Last change on this file since 94460 was 94460, checked in by vboxsync, 3 years ago

VBox/ostypes.h+Main/Global,Machine,UnattendedInstaller+FE/Qt: First pass
at updating the variety of Linux OS subtypes used at install time along
with their corresponding recommended installation defaults based on each
vendor's respective documentation. bugref:5936

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

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