VirtualBox

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

Last change on this file since 47294 was 47294, checked in by vboxsync, 12 years ago

Guest user state reporting: Update.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette