VirtualBox

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

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

VMMDev: when logging the Guest Additions OS type, explictely mention if the guest is 32-bit or 64-bit

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