VirtualBox

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

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

VMMDev.cpp: Build fixes.

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

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