VirtualBox

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

Last change on this file since 58162 was 58162, checked in by vboxsync, 9 years ago

VMMDev: Bumped saved state version to save heartbeat state. Wrote short section in the VMMDev @page about the heartbeat stuff.

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