VirtualBox

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

Last change on this file since 82968 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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