VirtualBox

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

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

VMMDev: Corrected some statistics.

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