VirtualBox

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

Last change on this file since 49469 was 49426, checked in by vboxsync, 11 years ago

VMMDev: check parameter.

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