VirtualBox

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

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

Update PDMDEVREG initialization comment so they refer to pfnMemSetup instead of pfnIOCtl.

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