VirtualBox

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

Last change on this file since 52934 was 52789, checked in by vboxsync, 10 years ago

VMMDev/Main, Additions: Guest heartbeat implementation. VMMDev reports to host log if missed heartbeat from the guest.

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