VirtualBox

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

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

Devices: Must not use PAGE_SIZE, PAGE_SHIFT, PAGE_OFFSET_MASK, PAGE_ADDRESS or PHYS_PAGE_ADDRESS here either. bugref:9898

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