VirtualBox

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

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

Devices: use LogRelMax were appropriate

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