VirtualBox

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

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

VMMDev: Preserve display change data in saved state, bugref:10134.

This commit fixes an issue when guest displays with ID > 0 became
automatically disabled on first resize after VM was restored from saved state.

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

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