VirtualBox

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

Last change on this file since 89121 was 87767, checked in by vboxsync, 4 years ago

VMM/TM,Devices/*: Changed the device and usb timer callbacks to take a timer handle rather than a pointer. Try a little harder using it. bugref:9943

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