VirtualBox

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

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

done

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