VirtualBox

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

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

VMMDev: Do proper heap usage accounting for HGCM requests. bugref:9379

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